I'm trying to create a multiple-choice test with approximately 100 questions in it. In this example, I give you a group of radio buttons. I solved creating multiple radio buttons with this code. However, I want to group these selections.
I found a soultion in this link : https://www.delftstack.com/tutorial/pyqt5/pyqt5-radiobutton/#:~:text=setChecked(True)-,PyQt5%20QRadiobutton%20Group,are%20connected%20to%20different%20functions.
However, they didn't create radio buttons with 'for' loop. What should I do about this?
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui, QtWidgets
class Ornek(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.toggles = []
self.lay = QVBoxLayout()
self.h_box = QGridLayout()
for i in range (4):
self.btngroup = QButtonGroup()
for j in range (4):
if j % 4 == 0:
self.btn = QRadioButton("A", self)
elif j % 4 == 1:
self.btn = QRadioButton("B", self)
elif j % 4 == 2:
self.btn = QRadioButton("C", self)
else:
self.btn = QRadioButton("D", self)
text = self.btn.text()
self.btn.clicked.connect(lambda ch, text=text: print("\nclicked--> {}".format(text)))
self.h_box.addWidget(self.btn,i,j,1,1)
self.lay.addLayout(self.h_box)
self.setLayout(self.lay)
self.setGeometry(300,300,250,250)
self.setWindowTitle("Çıkış Projesi")
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
pencere = Ornek()
sys.exit(app.exec_())
You have created a QButtonGroup but you don't use it, your code can be rewritten as:
def initUI(self):
self.toggles = []
lay = QVBoxLayout(self)
h_box = QGridLayout()
lay.addLayout(h_box)
for i in range(4):
btngroup = QButtonGroup(self)
btngroup.buttonClicked.connect(lambda btn: print(btn.text()))
for j in range(4):
btn = QRadioButton()
btngroup.addButton(btn)
h_box.addWidget(btn, i, j, 1, 1)
if j % 4 == 0:
btn.setText("A")
elif j % 4 == 1:
btn.setText("B")
elif j % 4 == 2:
btn.setText("C")
else:
btn.setText("D")
self.setGeometry(300, 300, 250, 250)
self.setWindowTitle("Çıkış Projesi")
self.show()
Related
I have a simple user interface where I want to dynamically add frames and labels in a widget (as I will use these labels to transmit a video feed from my webcams).
In the following code I set a function where the user selects an integer which represents the number of labels(webcams) they want to see and then dynamically adds these labels& frames to the widget:
def loopCamFeed(self,n):
if (n % 2) == 0:
dividnd = n / 2
for i in range(2):
self.frame_12 = QFrame(self.ui.webcamWidget)
self.frame_12.setObjectName(u"frame_12")
self.frame_12.setFrameShape(QFrame.StyledPanel)
self.frame_12.setFrameShadow(QFrame.Raised)
self.horizontalLayout_14 = QHBoxLayout(self.frame_12)
self.horizontalLayout_14.setObjectName(u"horizontalLayout_14")
for i in range(int(dividnd)):
self.label_5 = QLabel("hello",self.frame_12)
self.label_5.setObjectName(u"label_5")
self.horizontalLayout_14.addWidget(self.label_5, 0, Qt.AlignHCenter)
self.ui.verticalLayout_15.addWidget(self.frame_12)
Which displays the labels as in the image below:
--By adding a value of 2:
--By adding a value of 4):
By adding a value of 8:
The challenge that I am facing is how to handle an odd number selection. For example, if a user selects 3 or 7 webcams/labels.
If a user selects 3 labels/webcams, I'd want to show one on the top frame and two at the bottom.
MAIN.PY (Where this piece of code was written):
from ui_interface import *
import sys
from Custom_Widgets.Widgets import *
import cv2
import numpy as np
from PyQt5.QtCore import pyqtSignal, QObject, QThread
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
loadJsonStyle(self, self.ui)
self.show()
#Expand Center Menu Widget
self.ui.settingsBtn.clicked.connect(lambda: self.ui.centerMenuContainer.expandMenu())
self.ui.infoBtn.clicked.connect(lambda: self.ui.centerMenuContainer.expandMenu())
self.ui.helpBtn.clicked.connect(lambda: self.ui.centerMenuContainer.expandMenu())
#Close Center Menu Widget
self.ui.closeCenterMenuButton.clicked.connect(lambda: self.ui.centerMenuContainer.collapseMenu())
#Close Notification Menu Widget
self.ui.closeNotificationBtn.clicked.connect(lambda: self.ui.popUpNotificationContainer.collapseMenu())
self.loopCamFeed(4)
def ImageUpdateSlot(self, Image):
self.ui.label_5.setPixmap(QPixmap.fromImage(Image))
def CancelFeed(self):
self.worker1.stop()
def startVideo(self):
self.worker1 = Worker1()
self.worker1.start()
self.worker1.ImageUpdate.connect(self.ImageUpdateSlot)
def loopCamFeed(self,n):
if (n % 2) == 0:
dividnd = n / 2
for i in range(2):
self.frame_12 = QFrame(self.ui.webcamWidget)
self.frame_12.setObjectName(u"frame_12")
self.frame_12.setFrameShape(QFrame.StyledPanel)
self.frame_12.setFrameShadow(QFrame.Raised)
self.horizontalLayout_14 = QHBoxLayout(self.frame_12)
self.horizontalLayout_14.setObjectName(u"horizontalLayout_14")
for i in range(int(dividnd)):
self.label_5 = QLabel("hello",self.frame_12)
self.label_5.setObjectName(u"label_5")
self.horizontalLayout_14.addWidget(self.label_5, 0, Qt.AlignHCenter)
self.ui.verticalLayout_15.addWidget(self.frame_12)
class Worker1(QThread):
ImageUpdate = pyqtSignal(QImage)
def __init__(self):
super().__init__()
def run(self):
self.ThreadActive = True
Capture = cv2.VideoCapture(0)
while self.ThreadActive:
ret, frame = Capture.read()
if ret:
Image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
FlippedImage = cv2.flip(Image, 1)
ConvertToQtFormat = QImage(FlippedImage.data, FlippedImage.shape[1], FlippedImage.shape[0], QImage.Format_RGB888)
Pic = ConvertToQtFormat.scaled(1200, 900, Qt.KeepAspectRatio)
self.ImageUpdate.emit(Pic)
def stop(self):
self.ThreadActive = False
self.quit()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Use a grid layout instead of a horizontal layout:
def loopCamFeed(self,n):
self.frame_12 = QFrame(self.ui.webcamWidget)
self.frame_12.setObjectName(u"frame_12")
self.frame_12.setFrameShape(QFrame.StyledPanel)
self.frame_12.setFrameShadow(QFrame.Raised)
self.grid_layout = QGridLayout(self.frame_12)
self.grid_layout.setObjectName(u"grid_layout")
for i in range(int(n)):
self.label_5 = QLabel("hello",self.frame_12)
self.label_5.setObjectName(u"label_5")
self.grid_layout.addWidget(self.label_5, 0, Qt.AlignHCenter)
self.ui.verticalLayout_15.addWidget(self.frame_12)
As Medhat mentioned, applying the GridLayout was the best solution.
I applied the following code:
def loopCamFeed(self,n):
w = 0
if n > 0:
# if ( n % 2) == 0:
for i in range(int(n)):
if (i%2) == 0:
w +=1
print(int(w / 2), (i%2))
self.label = QtWidgets.QLabel()
self.label.setText("Screen " +str(i))
self.label.setStyleSheet("background-color: black5;")
self.label.setObjectName(u"label")
self.gridLayout.addWidget(self.label, (i%2) ,int(w),Qt.AlignHCenter )
This works perfectly! Thanks #Medhat
I have a grid layout that's inside a scroll area. I want to have 5 columns and 200 rows maximum at a time. When a grid item is clicked I want to remove all items in the grid and add new ones.
However, when I start with around 50 items(10x5) and add 1000(200x5) items after clearing the first 50 nothing shows up on the screen. I assume it is because they are too small.
If I do 750(150x5) they show up very small.
The issue is that if I start with 1000 items everything looks how they should be.
Below is my reproducible example to my problem.
import sys
from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import *
class GridButton(QPushButton):
def __init__(self, parent, tab, grid) -> None:
super().__init__(parent)
self.tab = tab
self.grid = grid
self.grid_wid = parent
def onclick(self):
self.tab.clear()
for i in range(150):
for j in range(5):
btn = GridButton(self.grid_wid, self.tab, self.grid)
btn.setText(f"nButton: {i}")
btn.clicked.connect(btn.onclick)
self.grid.addWidget(btn, i, j)
class Test(QWidget):
def __init__(self, parent) -> None:
super().__init__(parent)
self.sc = QScrollArea(self)
self.sc.setGeometry(0, 0, 1024, 600)
self.grid_wid = QWidget()
self.grid = QGridLayout(self.grid_wid)
for i in range(10):
for j in range(5):
btn = GridButton(self.grid_wid, self, self.grid)
btn.setText(f"Button: {i}")
btn.clicked.connect(btn.onclick)
self.grid.addWidget(btn, i, j)
self.sc.setWidget(self.grid_wid)
def clear(self):
for i in reversed(range(self.grid.count())):
widgetToRemove = self.grid.itemAt(i).widget()
widgetToRemove.setParent(None)
widgetToRemove.deleteLater()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.tabs = Test(self)
self.setWindowTitle("GUI")
self.setFixedSize(QSize(1024, 600))
self.setCentralWidget(self.tabs)
self.show()
def main():
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
From #CarlHR's answer:
self.sc.setWidgetResizable(True)
I am trying to create a basic 25 key keyboard in pyqt, I have laid out the 15 white keys but am struggling with how to add the 10 remaining black keys,
This is how I made my keys
from PyQt5.QtWidgets import QApplication, QPushButton
app = QApplication([])
top_win = QWidget()
set_color(top_win, Qt.cyan)
top_win.setAutoFillBackground(True)
top_win.show()
top_win.resize(1920,1080)
top_win.setWindowTitle("Synth-01")
top_vlayout = QVBoxLayout()
top_win.setLayout(top_vlayout)
keyboard = QWidget()
keyboard.setMaximumWidth(1410)
top_vlayout.addWidget(keyboard)
keyboard_layout = QHBoxLayout()
keyboard.setAutoFillBackground(True)
keyboard.setLayout(keyboard_layout)
for i in range(15):
name = "key_" + str(i)
name = QPushButton()
name.setMaximumWidth(94)
name.setMaximumHeight(349)
keyboard_layout.addWidget(name)
I now want to add the black keys inbetween like this
In this case, it is most preferable to use QGraphicsScene with QGraphicsItem, for this case I will use svg:
from PyQt5 import QtCore, QtGui, QtWidgets, QtSvg
class PianoKey(QtWidgets.QGraphicsRectItem):
def __init__(self, black=False, rect = QtCore.QRectF(), parent=None):
super(PianoKey, self).__init__(rect, parent)
self.m_pressed = False
self.m_selectedBrush = QtGui.QBrush()
self.m_brush = QtGui.QBrush(QtCore.Qt.black) if black else QtGui.QBrush(QtCore.Qt.white)
self.m_black = black
def setPressedBrush(self, brush):
self.m_selectedBrush = brush
def paint(self, painter, option, widget):
rendered = QtSvg.QSvgRenderer("key.svg")
black_pen = QtGui.QPen(QtCore.Qt.black, 1)
gray_pen = QtGui.QPen(QtGui.QBrush(QtCore.Qt.gray), 1,
QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
if self.m_pressed:
if self.m_selectedBrush.style() != QtCore.Qt.NoBrush:
painter.setBrush(self.m_selectedBrush)
else:
painter.setBrush(QtWidgets.QApplication.palette().highlight())
else:
painter.setBrush(self.m_brush);
painter.setPen(black_pen)
painter.drawRoundedRect(self.rect(), 15, 15, QtCore.Qt.RelativeSize)
if self.m_black:
rendered.render(painter, self.rect())
else:
points = [
QtCore.QPointF(self.rect().left()+1.5, self.rect().bottom()-1),
QtCore.QPointF(self.rect().right()-1, self.rect().bottom()-1),
QtCore.QPointF(self.rect().right()-1, self.rect().top()+1)
]
painter.setPen(gray_pen)
painter.drawPolyline(QtGui.QPolygonF(points))
def mousePressEvent(self, event):
self.m_pressed = True
self.update()
super(PianoKey, self).mousePressEvent(event)
event.accept()
def mouseReleaseEvent(self, event):
self.m_pressed = False
self.update()
super(PianoKey, self).mouseReleaseEvent(event)
KEYWIDTH, KEYHEIGHT = 18, 72
class PianoKeyBoard(QtWidgets.QGraphicsView):
def __init__(self, num_octaves=2, parent=None):
super(PianoKeyBoard, self).__init__(parent)
self.initialize()
self.m_numOctaves = num_octaves
scene = QtWidgets.QGraphicsScene(QtCore.QRectF(0, 0, KEYWIDTH * self.m_numOctaves * 7, KEYHEIGHT), self)
self.setScene(scene)
numkeys = self.m_numOctaves * 12
for i in range(numkeys):
octave = i//12*7
j = i % 12
if j >= 5: j += 1
if j % 2 == 0:
x = (octave + j/2)*KEYWIDTH
key = PianoKey(rect=QtCore.QRectF(x, 0, KEYWIDTH, KEYHEIGHT), black=False)
else:
x = (octave + j//2) * KEYWIDTH + KEYWIDTH * 6//10 + 1
key = PianoKey(rect=QtCore.QRectF(x, 0, KEYWIDTH * 8//10 - 1, KEYHEIGHT * 6//10 ), black=True)
key.setZValue(1)
key.setPressedBrush(QtWidgets.QApplication.palette().highlight())
self.scene().addItem(key)
def initialize(self):
self.setAttribute(QtCore.Qt.WA_InputMethodEnabled, False)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setCacheMode(QtWidgets.QGraphicsView.CacheBackground)
self.setViewportUpdateMode(QtWidgets.QGraphicsView.MinimalViewportUpdate)
self.setRenderHints(QtGui.QPainter.Antialiasing|
QtGui.QPainter.TextAntialiasing |
QtGui.QPainter.SmoothPixmapTransform)
self.setOptimizationFlag(QtWidgets.QGraphicsView.DontClipPainter, True)
self.setOptimizationFlag(QtWidgets.QGraphicsView.DontSavePainterState, True)
self.setOptimizationFlag(QtWidgets.QGraphicsView.DontAdjustForAntialiasing, True)
self.setBackgroundBrush(QtWidgets.QApplication.palette().base())
def resizeEvent(self, event):
super(PianoKeyBoard, self).resizeEvent(event)
self.fitInView(self.scene().sceneRect(), QtCore.Qt.KeepAspectRatio)
def sizeHint(self):
return self.mapFromScene(self.sceneRect()).boundingRect().size()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyle('fusion')
w = QtWidgets.QWidget()
lay = QtWidgets.QVBoxLayout(w)
lay.addWidget(QtWidgets.QLabel("Piano Keyboard", alignment=QtCore.Qt.AlignCenter))
lay.addWidget(PianoKeyBoard())
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
The complete code + key.svg can be found on this link
Here is my code,i want to add my list of items into qtabl widget in one key i have a list of items when i want to add my list of items in to qtable widget i am getting the problem i.e my last items is overriding the previous item because of the idx index in columns.i tried many ways but i not able to all the items in qtable widget.
Given below is my sample tried code:
from PyQt4 import QtCore, QtGui
from functools import partial
import os, sys
import time
from datetime import datetime
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
self.data_arraylist = {'85207':[{'item1':"Fruites", 'Qty':'10','Price':'100','total':'100'},{'item1':"Banana", 'Qty':'20','Price':'200','total':'200'}],'97895':{'item1':"vegitables", 'Qty':'2kg','Price':'200','total':'200'},'97055':{'item1':"snacks", 'Qty':'10p','Price':'200','total':'200'}}
super(MainWindow, self).__init__(parent)
self.dataw = QtGui.QWidget()
self._gridlayout = QtGui.QGridLayout()
self.vboxdata = QtGui.QVBoxLayout(self.dataw)
self.scrollArea = QtGui.QScrollArea()
self.vboxdata.addWidget(self.scrollArea)
self.scrollArea.setWidgetResizable(True)
self.vbox = QtGui.QVBoxLayout()
self.hbox1 = QtGui.QHBoxLayout()
self.timelabel = QtGui.QLabel()
self.orderbtn = QtGui.QPushButton("Orders")
self.newbtn = QtGui.QPushButton("New")
self.newbtn.clicked.connect(self.items_list)
self.hbox1.addWidget(self.timelabel)
self.hbox1.addWidget(self.orderbtn)
self.hbox1.addWidget(self.newbtn)
self.vbox.addLayout(self.hbox1)
self.mainLayout = QtGui.QGridLayout()
self.mainLayout.addWidget(self.dataw, 0, 0)
self.mainLayout.addLayout(self.vbox, 1, 0)
self.setCentralWidget(QtGui.QWidget(self))
self.centralWidget().setLayout(self.mainLayout)
def items_list(self):
self.mainw2 = QtGui.QWidget()
self.scrollArea.setWidget(self.mainw2)
self.newvbox = QtGui.QVBoxLayout(self.mainw2)
self.linedit = QtGui.QLineEdit()
self.search = QtGui.QLabel("Search")
self.newhbox = QtGui.QHBoxLayout()
self.newhbox.addWidget(self.linedit)
self.newhbox.addWidget(self.search)
self.newvbox.addLayout(self.newhbox)
self.table = QtGui.QTableWidget()
self.table_item = QtGui.QTableWidgetItem()
self.table.setRowCount(5)
self.table.verticalHeader().hide()
self.table.setColumnCount(5)
self.table.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.table.setHorizontalHeaderLabels(("S.no, Item Description,Qty,Rate(Rs:),Total").split(','))
self.newvbox.addWidget(self.table)
def keyPressEvent(self, event):
print event,event.key(),QtCore.Qt.Key_Return
if event.key() == QtCore.Qt.Key_Return:
text_key = self.linedit.text()
self.searchitems(text_key)
def searchitems(self,text_key):
if str(text_key) in self.data_arraylist:
for ridx,row in enumerate(range(1)):
for idx, column in enumerate(range(5)):
if idx ==0:
self.table.setItem(row,column,QtGui.QTableWidgetItem(str(ridx+1)))
elif idx ==1:
for i in range(len(self.data_arraylist[str(text_key)])):
self.table.setItem(row,column,QtGui.QTableWidgetItem(
str(self.data_arraylist[str(text_key)][i][
'item1'])))
elif idx ==2:
for i in range(len(self.data_arraylist[str(text_key)])):
self.table.setItem(row,column,
QtGui.QTableWidgetItem(str(
self.data_arraylist[str(
text_key)][i]['Qty'])))
elif idx ==3:
for i in range(len(self.data_arraylist[str(text_key)])):
self.table.setItem(row,column,QtGui.QTableWidgetItem(str(self.data_arraylist[str(text_key)][i]['Price'])))
elif idx ==4:
for i in range(len(self.data_arraylist[str(text_key)])):
self.table.setItem(row,column,QtGui.QTableWidgetItem(str(self.data_arraylist[str(text_key)][i]['total'])))
else:
pass
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
w = MainWindow()
w.show()
w.setGeometry(500,500,800,400)
sys.exit(app.exec_())
I am trying to set a custom property of an image inserted into a QTextEdit. I have the following example code which sets then outputs the value of the property to the terminal:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class TestEditor(QWidget):
def __init__(self):
QWidget.__init__(self)
layout = QVBoxLayout()
self.setLayout(layout)
self.layout().setSpacing(0)
self.layout().setContentsMargins(0, 0, 0, 0)
self.textEdit = QTextEdit()
self.layout().addWidget(self.textEdit)
document = self.textEdit.document()
cursor = QTextCursor(document)
cursor.insertImage("./testimage.png")
f = cursor.charFormat()
print(f)
prop_id = 0x100000 + 1
f.setProperty(prop_id, 100)
print(f.intProperty(prop_id))
print('------')
block = document.firstBlock()
while block.length() > 0:
print(block)
it = block.begin()
while not it.atEnd():
f = it.fragment()
fmt = f.charFormat()
print(fmt)
print(fmt.intProperty(prop_id))
it += 1
block = block.next()
class TestWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self.initUi()
def initUi(self):
layout = QVBoxLayout()
layout.addWidget(HextEditor())
self.setLayout(layout)
self.layout().setSpacing(0)
self.layout().setContentsMargins(0, 0, 0, 0)
self.setWindowTitle('button tooltip')
self.show()
def main():
app = QApplication(sys.argv)
window = TestWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The program results in an output of:
<PyQt5.QtGui.QTextCharFormat object at 0x107109ba8>
100
------
<PyQt5.QtGui.QTextBlock object at 0x105448318>
<PyQt5.QtGui.QTextCharFormat object at 0x107109ba8>
0
Note that the second time the value is gotten it has a value of 0 rather than 100. It even appears to be the same instance of a QTextCharFormat. How would I accomplish something like this? Am I missing something simple here?
I solved this by saving the range of the inserted image, selecting it, and using QTextCursor.setCharFormat() to save the changes:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class TestEditor(QWidget):
def __init__(self):
QWidget.__init__(self)
layout = QVBoxLayout()
self.setLayout(layout)
self.layout().setSpacing(0)
self.layout().setContentsMargins(0, 0, 0, 0)
self.textEdit = QTextEdit()
self.layout().addWidget(self.textEdit)
document = self.textEdit.document()
cursor = QTextCursor(document)
# Save the position of the beginning and end of the inserted image
p1 = cursor.position()
cursor.insertImage("./testimage.png")
p2 = cursor.position()
f = cursor.charFormat()
print(f)
prop_id = 0x100000 + 1
f.setProperty(prop_id, 100)
# Select the inserted fragment and apply format
cursor.setPosition(p1)
cursor.setPosition(p2, QTextCursor.KeepAnchor)
cursor.setCharFormat(f)
print(f.intProperty(prop_id))
print('------')
block = document.firstBlock()
while block.length() > 0:
print(block)
it = block.begin()
while not it.atEnd():
f = it.fragment()
fmt = f.charFormat()
print(fmt)
print(fmt.intProperty(prop_id))
it += 1
block = block.next()
class TestWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self.initUi()
def initUi(self):
layout = QVBoxLayout()
layout.addWidget(TestEditor())
self.setLayout(layout)
self.layout().setSpacing(0)
self.layout().setContentsMargins(0, 0, 0, 0)
self.setWindowTitle('button tooltip')
self.show()
def main():
app = QApplication(sys.argv)
window = TestWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()