I have three main sections of a main window, where the left side (critical data) should take the entire height of the window, while the data on the right should be split between top and bottom. Data in the lower right is related, but not critical - which is why I'd like it to be un-dockable/closable.
The Qt documentation shows an example of this in C++, but I have no idea how to turn this into Python code, as I have no C++ experience.
The Qt Designer application limits the user to Left/Right/Top/Bottom, and limiting the maximum width of the widget doesn't allow me to occupy the un-used space (i.e. doesn't allow the list widget on the left to take up the full height of the main window)
Long story short, to get a Qdockwidget into the lower right corner, you have to put another dock widget above it (it's still limited to Right/Left/Top/Bottom DockWidgetArea). After looking at the answer from eyllanesc below, I'll post two solutions. First, a simplified version of his code and then a modified version of the code I originally posted.
Eyllanesc's translation from the C++ example from I mentioned above:
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.resize(600, 600)
self.centralWidget = QtGui.QTextEdit()
self.setCentralWidget(self.centralWidget)
# Upper table widget
dock = QtGui.QDockWidget("Upper", self.centralWidget)
dock.setAllowedAreas(QtCore.Qt.RightDockWidgetArea)
self.tableWidget = QtGui.QTableWidget(dock)
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(6)
self.tableWidget.setRowCount(7)
for i in range(7):
item = QtGui.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(i, item)
self.tableWidget.verticalHeaderItem(i).setText("Item " + str(i + 1))
for i in range(6):
item = QtGui.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(i, item)
dock.setWidget(self.tableWidget)
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
# Lower table widget
dock = QtGui.QDockWidget("Lower", self.centralWidget)
self.tableWidget_2 = QtGui.QTableWidget(dock)
self.tableWidget_2.setObjectName("tableWidget_2")
self.tableWidget_2.setColumnCount(6)
self.tableWidget_2.setRowCount(7)
for i in range(7):
item = QtGui.QTableWidgetItem()
self.tableWidget_2.setVerticalHeaderItem(i, item)
for i in range(6):
item = QtGui.QTableWidgetItem()
self.tableWidget_2.setHorizontalHeaderItem(i, item)
dock.setWidget(self.tableWidget_2);
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
self.listWidget = QtGui.QListWidget(self.centralWidget)
self.listWidget.setLayoutDirection(QtCore.Qt.RightToLeft)
self.listWidget.setObjectName("listWidget")
for i in range(10):
item = QtGui.QListWidgetItem()
self.listWidget.addItem(item)
item = self.listWidget.item(i)
item.setText("Item " + str(i + 1))
self.listWidget.setMinimumSize(QtCore.QSize(340, 600))
self.setWindowTitle("Dock Widgets")
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
And the modified version of the code I originally used:
from PyQt4 import QtCore, QtGui
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtGui.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.listWidget = QtGui.QListWidget(self.centralwidget)
self.listWidget.setObjectName("listWidget")
self.gridLayout.addWidget(self.listWidget, 0, 0, 1, 1)
self.listWidget.setLayoutDirection(QtCore.Qt.RightToLeft)
for i in range(10):
item = QtGui.QListWidgetItem()
self.listWidget.addItem(item)
item = self.listWidget.item(i)
item.setText("Item " + str(i + 1))
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 26))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.dockWidget = QtGui.QDockWidget(MainWindow)
self.dockWidget.setFeatures(QtGui.QDockWidget.DockWidgetFloatable)
self.dockWidget.setObjectName("dockWidget")
self.dockWidgetContents = QtGui.QWidget()
self.dockWidgetContents.setObjectName("dockWidgetContents")
self.tableWidget = QtGui.QTableWidget(self.dockWidgetContents)
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(6)
self.tableWidget.setRowCount(7)
for i in range(7):
item = QtGui.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(i, item)
self.tableWidget.verticalHeaderItem(i).setText("Item " + str(i + 1))
for i in range(6):
item = QtGui.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(i, item)
self.gridLayout_2 = QtGui.QGridLayout(self.dockWidgetContents)
self.gridLayout_2.setObjectName("gridLayout_2")
self.gridLayout_2.addWidget(self.tableWidget, 0, 0, 1, 1)
self.dockWidget.setWidget(self.dockWidgetContents)
MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.dockWidget)
self.dockWidget_2 = QtGui.QDockWidget(MainWindow)
self.dockWidget_2.setFeatures(QtGui.QDockWidget.DockWidgetClosable|QtGui.QDockWidget.DockWidgetFloatable)
self.dockWidget_2.setObjectName("dockWidget_2")
self.dockWidgetContents_2 = QtGui.QWidget()
self.dockWidgetContents_2.setObjectName("dockWidgetContents_2")
self.gridLayout_3 = QtGui.QGridLayout(self.dockWidgetContents_2)
self.gridLayout_3.setObjectName("gridLayout_3")
self.tableWidget_2 = QtGui.QTableWidget(self.dockWidgetContents)
self.tableWidget_2.setObjectName("tableWidget_2")
self.tableWidget_2.setColumnCount(6)
self.tableWidget_2.setRowCount(7)
for i in range(7):
item = QtGui.QTableWidgetItem()
self.tableWidget_2.setVerticalHeaderItem(i, item)
for i in range(6):
item = QtGui.QTableWidgetItem()
self.tableWidget_2.setHorizontalHeaderItem(i, item)
self.gridLayout_3.addWidget(self.tableWidget_2, 0, 0, 1, 1)
self.dockWidget_2.setWidget(self.dockWidgetContents_2)
MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.dockWidget_2)
MainWindow.setWindowTitle("MainWindow")
QtCore.QMetaObject.connectSlotsByName(MainWindow)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())## Heading ##
My answer is a translation of this example: http://doc.qt.io/qt-5/qtwidgets-mainwindows-dockwidgets-example.html, so future readers can use it to make a translation from the C++ code to Python.
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.textEdit = QtGui.QTextEdit()
self.setCentralWidget(self.textEdit)
self.createActions()
self.createStatusBar()
self.createDockWindows()
self.setWindowTitle("Dock Widgets")
self.newLetter()
self.setUnifiedTitleAndToolBarOnMac(True)
def newLetter(self):
self.textEdit.clear()
cursor = QtGui.QTextCursor(self.textEdit.textCursor())
cursor.movePosition(QtGui.QTextCursor.Start)
topFrame = cursor.currentFrame()
topFrameFormat = topFrame.frameFormat()
topFrameFormat.setPadding(16)
topFrame.setFrameFormat(topFrameFormat)
textFormat = QtGui.QTextCharFormat()
boldFormat = QtGui.QTextCharFormat()
boldFormat.setFontWeight(QtGui.QFont.Bold)
italicFormat = QtGui.QTextCharFormat()
italicFormat.setFontItalic(True)
tableFormat = QtGui.QTextTableFormat()
tableFormat.setBorder(1)
tableFormat.setCellPadding(16)
tableFormat.setAlignment(QtCore.Qt.AlignRight)
cursor.insertTable(1, 1, tableFormat)
cursor.insertText("The Firm", boldFormat)
cursor.insertBlock()
cursor.insertText("321 City Street", textFormat)
cursor.insertBlock()
cursor.insertText("Industry Park")
cursor.insertBlock()
cursor.insertText("Some Country")
cursor.setPosition(topFrame.lastPosition())
cursor.insertText(QtCore.QDate.currentDate().toString("d MMMM yyyy"), textFormat)
cursor.insertBlock()
cursor.insertBlock()
cursor.insertText("Dear ", textFormat)
cursor.insertText("NAME", italicFormat)
cursor.insertText(",", textFormat)
for i in range(3):
cursor.insertBlock()
cursor.insertText("Yours sincerely,", textFormat)
for i in range(3):
cursor.insertBlock()
cursor.insertText("The Boss", textFormat)
cursor.insertBlock()
cursor.insertText("ADDRESS", italicFormat)
def print_(self):
document = self.textEdit.document()
printer = QtGui.QPrinter()
dlg = QtGui.QPrintDialog(printer, self)
if dlg.exec() != QtGui.QDialog.Accepted:
return
document.print_(printer)
self.statusBar().showMessage("Ready", 2000)
def save(self):
fileName = QtGui.QFileDialog.getSaveFileName(self,
"Choose a file name", ".", "HTML document (*.html *.htm)")
if not fileName:
return
file = QtCore.QFile(fileName)
if not file.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text):
QtGui.QMessageBox.warning(self, "Dock Widgets",
"Cannot write file {}:\n{}."
.format(QtCore.QDir.toNativeSeparators(fileName), file.errorString()))
return
out = QTextStream(file)
QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
out << textEdit.toHtml()
QtGui.QApplication.restoreOverrideCursor()
self.statusBar().showMessage("Saved '{}'".format(fileName), 2000)
def undo(self):
document = self.textEdit.document()
document.undo()
def insertCustomer(self, customer):
if not customer:
return
customerList = customer.split(", ")
document = self.textEdit.document()
cursor = document.find("NAME")
if not cursor.isNull():
cursor.beginEditBlock()
cursor.insertText(customerList[0])
oldcursor = cursor
cursor = document.find("ADDRESS")
if not cursor.isNull():
for c in customerList:
cursor.insertBlock()
cursor.insertText(c)
cursor.endEditBlock()
else:
oldcursor.endEditBlock()
def addParagraph(self, paragraph):
if not paragraph:
return
document = self.textEdit.document()
cursor = document.find("Yours sincerely,")
if cursor.isNull():
return
cursor.beginEditBlock()
cursor.movePosition(QtGui.QTextCursor.PreviousBlock, QtGui.QTextCursor.MoveAnchor, 2)
cursor.insertBlock()
cursor.insertText(paragraph)
cursor.insertBlock()
cursor.endEditBlock()
def about(self):
QtGui.QMessageBox.about(self, "About Dock Widgets",
"The <b>Dock Widgets</b> example demonstrates how to "
"use Qt's dock widgets. You can enter your own text, "
"click a customer to add a customer name and "
"address, and click standard paragraphs to add them.")
def createActions(self):
fileMenu = self.menuBar().addMenu("&File")
fileToolBar = self.addToolBar("File")
newIcon = QtGui.QIcon.fromTheme("document-new", QtGui.QIcon(":/images/new.png"))
newLetterAct = QtGui.QAction(newIcon, "&New Letter", self)
newLetterAct.setShortcuts(QtGui.QKeySequence.New)
newLetterAct.setStatusTip("Create a new form letter")
newLetterAct.triggered.connect(self.newLetter)
fileMenu.addAction(newLetterAct)
fileToolBar.addAction(newLetterAct)
saveIcon = QtGui.QIcon.fromTheme("document-save", QtGui.QIcon(":/images/save.png"))
saveAct = QtGui.QAction(saveIcon, "&Save...", self)
saveAct.setShortcuts(QtGui.QKeySequence.Save)
saveAct.setStatusTip("Save the current form letter")
saveAct.triggered.connect(self.save)
fileMenu.addAction(saveAct)
fileToolBar.addAction(saveAct)
printIcon = QtGui.QIcon.fromTheme("document-print", QtGui.QIcon(":/images/print.png"))
printAct = QtGui.QAction(printIcon,"&Print...", self)
printAct.setShortcuts(QtGui.QKeySequence.Print)
printAct.setStatusTip("Print the current form letter")
printAct.triggered.connect(self.print_)
fileMenu.addAction(printAct)
fileToolBar.addAction(printAct)
fileMenu.addSeparator()
quitAct = fileMenu.addAction("&Quit", self.close)
quitAct.setShortcuts(QtGui.QKeySequence.Quit)
quitAct.setStatusTip("Quit the application")
editMenu = self.menuBar().addMenu("&Edit")
editToolBar = self.addToolBar("Edit")
undoIcon = QtGui.QIcon.fromTheme("edit-undo", QtGui.QIcon(":/images/undo.png"))
undoAct = QtGui.QAction(undoIcon, "&Undo", self)
undoAct.setShortcuts(QtGui.QKeySequence.Undo)
undoAct.setStatusTip("Undo the last editing action")
undoAct.triggered.connect(self.undo)
editMenu.addAction(undoAct)
editToolBar.addAction(undoAct)
self.viewMenu = self.menuBar().addMenu("&View")
self.menuBar().addSeparator()
helpMenu = self.menuBar().addMenu("&Help")
aboutAct = helpMenu.addAction("&About", self.about)
aboutAct.setStatusTip("Show the application's About box")
aboutQtAct = helpMenu.addAction("About &Qt", QtGui.qApp.aboutQt)
aboutQtAct.setStatusTip("Show the Qt library's About box")
def createStatusBar(self):
self.statusBar().showMessage("Ready")
def createDockWindows(self):
dock = QtGui.QDockWidget("Customers", self)
dock.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea)
self.customerList = QtGui.QListWidget(dock)
self.customerList.addItems([
"John Doe, Harmony Enterprises, 12 Lakeside, Ambleton",
"Jane Doe, Memorabilia, 23 Watersedge, Beaton",
"Tammy Shea, Tiblanka, 38 Sea Views, Carlton",
"Tim Sheen, Caraba Gifts, 48 Ocean Way, Deal",
"Sol Harvey, Chicos Coffee, 53 New Springs, Eccleston",
"Sally Hobart, Tiroli Tea, 67 Long River, Fedula"])
dock.setWidget(self.customerList)
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
self.viewMenu.addAction(dock.toggleViewAction())
dock = QtGui.QDockWidget("Paragraphs", self)
self.paragraphsList = QtGui.QListWidget(dock)
self.paragraphsList.addItems([
"""Thank you for your payment which we have received today.""",
"""Your order has been dispatched and should be with you \
within 28 days.""",
"""We have dispatched those items that were in stock. The \
rest of your order will be dispatched once all the \
remaining items have arrived at our warehouse. No \
additional shipping charges will be made.""",
"""You made a small overpayment (less than $5) which we \
will keep on account for you, or return at your request.""",
"""You made a small underpayment (less than $1), but we have \
sent your order anyway. We'll add this underpayment to \
your next bill.""",
"""Unfortunately you did not send enough money. Please remit \
an additional $. Your order will be dispatched as soon as \
the complete amount has been received.""",
"""You made an overpayment (more than $5). Do you wish to \
buy more items, or should we return the excess to you?"""])
dock.setWidget(self.paragraphsList);
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
self.viewMenu.addAction(dock.toggleViewAction())
self.customerList.currentTextChanged.connect(self.insertCustomer)
self.paragraphsList.currentTextChanged.connect(self.addParagraph)
# import dockwidgets_rc
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
The complete example can be found at the following link. The .qrc file has been compiled for Python 2 (dockwidgets_rc.py), but for Python 3 you must recompile the file.
Related
Hi guys I want the user to choose the motor speed before going into step. So, in the first class, I made the first window which asked for the motor speed and another one is the recording and predicting process. In the recording process, I want to collect the WAV file as future data and use the motor speed as a file name. But I cannot pass the self.RPM value from one class to another. This is some part of the code.
class Ui_Form(object):
def setupUi(self, Form):
#The rest of the code
def retranslateUi(self, Form):
#The rest of the code
def start_click(self):
print('Start button click')
_translate = QtCore.QCoreApplication.translate
self.label.setText(_translate("Form", "<html><head/><body><p align=\"center\"><span style=\" color:#000000;\">Recording</span></p></body></html>"))
app.processEvents()
time.sleep(1)
count = 0
round = 0
for i in range(3):
round = i + 1
text = "Round " + str(round) + "/3"
self.label.setText(text)
app.processEvents()
print(text)
#Recording
now = datetime.now()
day = now.strftime("%d")
month = now.strftime("%m")
year = now.strftime("%y")
hour = now.strftime("%H")
minute = now.strftime("%M")
second = now.strftime("%S")
print(day,"/",month,"/",year,hour,":",minute,":",second)
CHUNK = 1024 #The number of frames in the buffer
FORMAT = pyaudio.paInt16
CHANNELS = 1 #Each frame will have 2 samples
RATE = 44100 #The number of samples collected per second or we can called sample rate
RECORD_SECONDS = 2 #Duration of recording
WAVE_OUTPUT_FILENAME = f"Data2/Test/{day}{month}{year}_{hour}{minute}{second}.wav" <--- I want to add RPM value here
p = pyaudio.PyAudio()
stream = p.open(format = FORMAT, channels = CHANNELS, rate = RATE, input = True, frames_per_buffer = CHUNK)
print("* recording")
frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK) #read audio data from the stream
frames.append(data)
print("* done recording")
self.label.setText(_translate("Form", "<html><head/><body><p align=\"center\"><span style=\" color:#000000;\">Done Recording</span></p></body></html>"))
stream.stop_stream()
stream.close()
p.terminate()
wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb') # 'rb' read only, 'wb' write only
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames)) #
wf.close()
#The rest of the code
class Ui_Form2(object):
def openWindow(self):
self.window = QtWidgets.QWidget()
self.ui = Ui_Form()
self.ui.setupUi(self.window)
self.window.show()
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(422, 202)
Form.setFixedSize(422, 202)
self.pushButton = QtWidgets.QPushButton(Form, clicked = lambda: self.openWindow())
self.pushButton.setGeometry(QtCore.QRect(10, 120, 121, 71))
font = QtGui.QFont()
font.setPointSize(15)
self.pushButton.setFont(font)
self.pushButton.setObjectName("pushButton")
self.pushButton_2 = QtWidgets.QPushButton(Form, clicked = lambda: self.openWindow())
self.pushButton_2.setGeometry(QtCore.QRect(150, 120, 121, 71))
font = QtGui.QFont()
font.setPointSize(15)
self.pushButton_2.setFont(font)
self.pushButton_2.setObjectName("pushButton_2")
self.pushButton_3 = QtWidgets.QPushButton(Form, clicked = lambda: self.openWindow())
self.pushButton_3.setGeometry(QtCore.QRect(290, 120, 121, 71))
font = QtGui.QFont()
font.setPointSize(15)
self.pushButton_3.setFont(font)
self.pushButton_3.setObjectName("pushButton_3")
self.label = QtWidgets.QLabel(Form)
self.label.setGeometry(QtCore.QRect(70, 20, 281, 81))
self.label.setFrameShape(QtWidgets.QFrame.WinPanel)
self.label.setFrameShadow(QtWidgets.QFrame.Sunken)
self.label.setObjectName("label")
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.pushButton.setText(_translate("Form", "1300 RPM"))
self.pushButton.clicked.connect(lambda: self.rpm_button_clicked(self.pushButton.text()))
self.pushButton_2.setText(_translate("Form", "1500 RPM"))
self.pushButton_2.clicked.connect(lambda: self.rpm_button_clicked(self.pushButton_2.text()))
self.pushButton_3.setText(_translate("Form", "1800 RPM"))
self.pushButton_3.clicked.connect(lambda: self.rpm_button_clicked(self.pushButton_3.text()))
self.label.setText(_translate("Form", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">RPM Selection</span></p></body></html>"))
def rpm_button_clicked(self, button_text):
rpm_values = {'1300 RPM': 1300, '1500 RPM': 1500, '1800 RPM': 1800}
self.RPM = rpm_values[button_text]
print(self.RPM)
if __name__ == "__main__":
Form = QtWidgets.QWidget()
ui = Ui_Form2()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
I want to use the value from one class on another or anyone got a better idea than this can suggest
Either you use signal/slots (a Qt mechanism for observer/observable), or do it the Python object way.
Signal and slot
In the first case, you need to declare a signal in the class (A) where you select the motor speed, then in your other class (B) you connect the signal for your instance of A to a slot in your B instance.
When doing Qt graphical applications, I prefer to use toy examples to better understand how it works.
Here is what I mean :
import sys
from typing import Optional
from PyQt5 import QtWidgets, QtCore
class WindowA(QtWidgets.QMainWindow):
def __init__(self):
super().__init__(parent=None)
self.setWindowTitle("A")
central_widget = QtWidgets.QPushButton("Choose")
central_widget.clicked.connect(self.on_button_Choose_pushed)
self.setCentralWidget(central_widget)
def on_button_Choose_pushed(self, checked: bool) -> None:
print("'choose' button clicked")
file_dialog = QtWidgets.QFileDialog(parent=self)
if file_dialog.exec():
print("a file was selected")
filenames = file_dialog.selectedFiles()
print(filenames)
assert len(filenames) == 1
print("emitting the signal")
self.file_selected.emit(filenames[0])
else:
print("no file selected")
file_selected = QtCore.pyqtSignal(str)
class WindowB(QtWidgets.QMainWindow):
def __init__(self, window_a: WindowA):
super().__init__(parent=None)
self.setWindowTitle("B")
self.filename: Optional[str] = None
central_widget = QtWidgets.QPushButton("Do something")
central_widget.clicked.connect(self.on_button_Do_Something_pushed)
self.setCentralWidget(central_widget)
window_a.file_selected.connect(self.on_file_selected)
def on_button_Do_Something_pushed(self, checked: bool) -> None:
print("'do something' button clicked")
print("filename is :", repr(self.filename))
# do something
#QtCore.pyqtSlot(str)
def on_file_selected(self, filename: str) -> None:
print("'file selected' slot received a signal, filename =", repr(filename))
self.filename = filename
def main() -> int:
app = QtWidgets.QApplication([])
window_a = WindowA()
window_a.setVisible(True)
window_b = WindowB(window_a) # passing A to B
window_b.setVisible(True)
return app.exec()
if __name__ == "__main__":
sys.exit(main())
(the 2 windows may appear one on top of the other)
Click the button B "do something" button, then the A button "choose" and select a file, then click B again. You will get :
'do something' button clicked
filename is : None
'choose' button clicked
a file was selected
['/home/stack_overflow/log.log']
emitting the signal
'file selected' slot received a signal, filename = '/home/stack_overflow/log.log'
'do something' button clicked
filename is : '/home/stack_overflow/log.log'
Just objects
This is the over way around. You need your A to know of B, so that when a file is selected from A, it sets the variable for B.
import sys
from typing import Optional
from PyQt5 import QtWidgets, QtCore
class WindowA(QtWidgets.QMainWindow):
def __init__(self, window_b: "WindowB"):
super().__init__(parent=None)
self.setWindowTitle("A")
self._window_b = window_b # save it for later
central_widget = QtWidgets.QPushButton("Choose")
central_widget.clicked.connect(self.on_button_Choose_pushed)
self.setCentralWidget(central_widget)
def on_button_Choose_pushed(self, checked: bool) -> None:
print("'choose' button clicked")
file_dialog = QtWidgets.QFileDialog(parent=self)
if file_dialog.exec():
print("a file was selected")
filenames = file_dialog.selectedFiles()
print(filenames)
assert len(filenames) == 1
print("setting the variable of B")
self._window_b.filename = filenames[0]
else:
print("no file selected")
class WindowB(QtWidgets.QMainWindow):
def __init__(self):
super().__init__(parent=None)
self.setWindowTitle("B")
self.filename: Optional[str] = None
central_widget = QtWidgets.QPushButton("Do something")
central_widget.clicked.connect(self.on_button_Do_Something_pushed)
self.setCentralWidget(central_widget)
def on_button_Do_Something_pushed(self, checked: bool) -> None:
print("'do something' button clicked")
print("filename is :", self.filename)
# do something
def main() -> int:
app = QtWidgets.QApplication([])
window_b = WindowB()
window_b.setVisible(True)
window_a = WindowA(window_b) # passing B to A
window_a.setVisible(True)
return app.exec()
if __name__ == "__main__":
sys.exit(main())
This way, A sets the variable of B.
Conclusion
If you understand these 2 techniques, you can change the structure. You can have a class containing the data, and the other being given a reference to the first class.
Or you could make the code that instantiate both of them (here is is the main() function) connect the signal from the first to the slot of the second.
Adapting a code from PyQt4 to PyQt6 I was able to simulate a QCheckBox (select all) in the QHeaderView of a QTableView. However, clicks in regions outside the QCheckBox rectangle in the same column or in other columns of the table, act on the QCheckBox.
class CheckBoxHeader(QtWidgets.QHeaderView):
clicked = QtCore.pyqtSignal(bool)
def __init__(self, orientation = Qt.Orientation.Horizontal, parent = None):
super(CheckBoxHeader,self).__init__(orientation, parent)
self.setSectionResizeMode(QtWidgets.QHeaderView.ResizeMode.Stretch)
self.isChecked = False
def paintSection(self, painter, rect, logicalIndex):
painter.save()
super(CheckBoxHeader,self).paintSection(painter, rect, logicalIndex)
painter.restore()
if logicalIndex==3:
option = QtWidgets.QStyleOptionButton()
option.rect= QtCore.QRect(503,1,20,20)
option.state= QtWidgets.QStyle.StateFlag.State_Enabled | QtWidgets.QStyle.StateFlag.State_Active
if self.isChecked:
option.state|= QtWidgets.QStyle.StateFlag.State_On
else:
option.state|= QtWidgets.QStyle.StateFlag.State_Off
self.style().drawControl(QtWidgets.QStyle.ControlElement.CE_CheckBox, option, painter)
def mousePressEvent(self, event):
if self.isChecked:
self.isChecked = False
else:
self.isChecked = True
self.clicked.emit(self.isChecked)
self.viewport().update()
class Ui_teste(object):
def setupUi(self, janela):
janela.setObjectName("cadastro_clientes")
janela.resize(700, 400)
janela.setAccessibleName("")
janela.setTabShape(QtWidgets.QTabWidget.TabShape.Rounded)
data = [
("Joe", "Senior Web Developerrwyeriweyrtiwyrtiwyetrwetruwtruw", "joe#example.com"),
("Lara", "Project Manager", "lara#example.com"),
("David", "Data Analyst", "david#example.com"),
("Jane", "Senior Python Developer", "jane#example.com"),
]
self.tableWidget = QtWidgets.QTableWidget(janela)
self.tableWidget.setGeometry(5,5,600,320)
self.tableWidget.setColumnCount(4)
self.tableWidget.setHorizontalHeaderLabels(["Nome", "Profissão", "Email"," "])
self.tableWidget.setRowCount(len(data))
self.header = CheckBoxHeader(parent=self.tableWidget)
self.header.setMaximumSectionSize(10)
self.header.clicked.connect(self.on_headerClick)
self.tableWidget.setHorizontalHeader(self.header)
self.tableWidget.show()
self.tableWidget.setRowCount(0)
for index, c in enumerate(data):
rows = self.tableWidget.rowCount()
self.tableWidget.setRowCount(rows + 1)
self.tableWidget.setItem(rows, 0, QtWidgets.QTableWidgetItem(str(c[0])))
self.tableWidget.setItem(rows, 1, QtWidgets.QTableWidgetItem(str(c[1])))
self.tableWidget.setItem(rows, 2, QtWidgets.QTableWidgetItem(str(c[2])))
pWidget = QtWidgets.QWidget()
pCheckBox = QtWidgets.QCheckBox()
pCheckBox.clicked.connect(self.on_changeCheckBox)
pLayout = QtWidgets.QHBoxLayout(pWidget)
pLayout.addWidget(pCheckBox)
pLayout.setAlignment(Qt.AlignmentFlag.AlignCenter)
pLayout.setContentsMargins(0,0,0,0)
pWidget.setLayout(pLayout)
self.tableWidget.setCellWidget(rows, 3, pWidget)
def on_headerClick(self,isCheck):
qtde_rows = self.tableWidget.rowCount()
if isCheck:
for i in range(qtde_rows):
self.tableWidget.cellWidget(i, 3).layout().itemAt(0).widget().setChecked(True)
else:
for i in range(qtde_rows):
self.tableWidget.cellWidget(i, 3).layout().itemAt(0).widget().setChecked(False)
#print(isCheck)
def on_changeCheckBox(self, isCheck):
if not isCheck:
self.tableWidget.horizontalHeader().isChecked = False
self.tableWidget.horizontalHeader().viewport().update()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
testes = QtWidgets.QMainWindow()
ui = Ui_teste()
ui.setupUi(testes)
testes.show()
sys.exit(app.exec())
What I need is for only the rectangle region of the QCheckBox to be selectable. Can anybody help me?
QTableView with QHeaderView and select all QCheckBox
I've spent a lot of time making GUIs using tkinter, but never used the OOP style so I wanted to start learning PyQt5 and in turn start learning OOP (definitely struggling through it).
I currently have three files:
app.py - "main entry point" for the application
main_menu.py - Python file converted from the PyQt designer .ui file
add_functions.py - file that will have functions to update GUI based on user actions and run functions from button clicks
My question is, how do I update the initial values of the combo boxes, outside of the "main_menu.py" file where the widgets are created? I'm assuming I do it somewhere in the "app.py" file, but I cannot figure it out.
The code below doesn't throw any errors, but the combo boxes are blank where one should be a list of strings and the other a single string (will later be updated based on first combo box selection)
I was able to get it to work with everything basically in the "main_menu.py" file, but then I realized every time I want to change the UI, it would create a problem.
app.py
from PyQt5.QtWidgets import QMainWindow
from PyQt5 import QtWidgets
# import GUI from designer file
from main_menu import Ui_main_menu
# import other functions
from add_functions import ChangeLists
class Main(QMainWindow, Ui_main_menu):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.setupUi(self)
# Team List
team_list_file = open(r'C:\NHLdb_pyqt\files\NHLteams.txt', 'r')
team_list = team_list_file.read().splitlines()
team_list_file.close()
print("team list: ", team_list)
# Initial Player List
player_list_init = "Please Select a Team"
# update combo box lists
print("team list: ", team_list)
self.team_select_combobox.addItems(team_list)
self.player_select_combobox.addItem(player_list_init)
# connect combo box to function that will change player list based on team list selection
# self.team_select_combobox.currentTextChanged.connect(ChangeLists.team_changed)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
main_menu = QtWidgets.QDialog()
ui = Ui_main_menu()
ui.setupUi(main_menu)
main_menu.show()
sys.exit(app.exec_())
main_menu.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_main_menu(object):
def setupUi(self, main_menu):
main_menu.setObjectName("main_menu")
main_menu.resize(463, 408)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(main_menu)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.tabWidget = QtWidgets.QTabWidget(main_menu)
self.tabWidget.setObjectName("tabWidget")
self.get_data_tab = QtWidgets.QWidget()
self.get_data_tab.setObjectName("get_data_tab")
self.verticalLayout = QtWidgets.QVBoxLayout(self.get_data_tab)
self.verticalLayout.setObjectName("verticalLayout")
self.team_player_layout = QtWidgets.QGridLayout()
self.team_player_layout.setObjectName("team_player_layout")
self.player_select_label = QtWidgets.QLabel(self.get_data_tab)
self.player_select_label.setAlignment(QtCore.Qt.AlignCenter)
self.player_select_label.setObjectName("player_select_label")
self.team_player_layout.addWidget(self.player_select_label, 2, 0, 1, 1)
self.team_select_combobox = QtWidgets.QComboBox(self.get_data_tab)
self.team_select_combobox.setCurrentText("")
self.team_select_combobox.setPlaceholderText("")
self.team_select_combobox.setObjectName("team_select_combobox")
self.team_player_layout.addWidget(self.team_select_combobox, 0, 1, 1, 1)
self.player_select_combobox = QtWidgets.QComboBox(self.get_data_tab)
self.player_select_combobox.setObjectName("player_select_combobox")
self.team_player_layout.addWidget(self.player_select_combobox, 2, 1, 1, 1)
self.team_select_label = QtWidgets.QLabel(self.get_data_tab)
self.team_select_label.setAlignment(QtCore.Qt.AlignCenter)
self.team_select_label.setObjectName("team_select_label")
self.team_player_layout.addWidget(self.team_select_label, 0, 0, 1, 1)
self.get_player_data_button = QtWidgets.QPushButton(self.get_data_tab)
self.get_player_data_button.setObjectName("get_player_data_button")
self.team_player_layout.addWidget(self.get_player_data_button, 3, 0, 1, 2)
self.verticalLayout.addLayout(self.team_player_layout)
self.tableWidget = QtWidgets.QTableWidget(self.get_data_tab)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.tableWidget.sizePolicy().hasHeightForWidth())
self.tableWidget.setSizePolicy(sizePolicy)
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(4)
self.tableWidget.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(2, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(3, item)
self.verticalLayout.addWidget(self.tableWidget)
self.tabWidget.addTab(self.get_data_tab, "")
self.view_db_tab = QtWidgets.QWidget()
self.view_db_tab.setObjectName("view_db_tab")
self.tabWidget.addTab(self.view_db_tab, "")
self.horizontalLayout_2.addWidget(self.tabWidget)
self.retranslateUi(main_menu)
self.tabWidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(main_menu)
def retranslateUi(self, main_menu):
_translate = QtCore.QCoreApplication.translate
main_menu.setWindowTitle(_translate("main_menu", "NHL Database"))
self.player_select_label.setText(_translate("main_menu", "Select A Player:"))
self.team_select_label.setText(_translate("main_menu", "Select A Team:"))
self.get_player_data_button.setText(_translate("main_menu", "Get Player Data"))
item = self.tableWidget.horizontalHeaderItem(0)
item.setText(_translate("main_menu", "Year"))
item = self.tableWidget.horizontalHeaderItem(1)
item.setText(_translate("main_menu", "Team"))
item = self.tableWidget.horizontalHeaderItem(2)
item.setText(_translate("main_menu", "League"))
item = self.tableWidget.horizontalHeaderItem(3)
item.setText(_translate("main_menu", "GP"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.get_data_tab), _translate("main_menu", "Get Player Data"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.view_db_tab), _translate("main_menu", "View Database"))
add_functions
from os import path
from PyQt5 import QtCore, QtGui, QtWidgets
class ChangeLists:
def team_changed(self):
index = self.team_select_combobox.currentText()
if index != 0 and path.exists(r'C:\NHLdb\files\_' + str(index) + '.txt'):
player_list_file = open(r'C:\NHLdb\files\_' + str(index) + '.txt', 'r')
player_list_update = player_list_file.read().splitlines()
player_list_file.close()
self.player_select_combobox.clear()
self.player_select_combobox.addItems(player_list_update)
if index != 0 and not path.exists(r'C:\NHLdb\files\_' + str(index) + '.txt'):
self.player_select_combobox.clear()
self.player_select_combobox.addItem("Prospects Not Compiled")
Your calling order in the app.py is a bit off. Class Main is never called and hence your intialization routine defined there never gets executed. Additionally, class Main inherits from the wrong Window type. In your case, you designed a QDialog, so it should inherit from that (instead of QMainWindow).
Upon fixing these issues, everything you defined in the Main class should work as expected:
modified app.py
from PyQt5 import QtWidgets
from main_menu import Ui_main_menu
class Main(QtWidgets.QDialog, Ui_main_menu):
def __init__(self):
super().__init__()
# setup ui
self.setupUi(self)
# Team List
team_list_file = open(r'D:\temp.txt', 'r')
team_list = team_list_file.read().splitlines()
team_list_file.close()
# Initial Player List
player_list_init = "Please Select a Team"
# update combo box lists
self.team_select_combobox.addItems(team_list)
self.player_select_combobox.addItem(player_list_init)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
ui = Main()
ui.show()
app.exec_()
Here in my sample code i want to display my dictionary data into scroll Area.I tried so many ways but i am not getting properly.i did n't get any error also.Can any one please tell me why my data is not displayed in scroll area.where i did the mistake in below program please guide me.Thank you in advance.
Given below is my sample code:
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.products_list = {
"Givers":{
"price": 140,
"Quantity": 100,
"Discount": 0,
"Total_price":14000,
"Paid_amount":14000},
"New_Member":{
"price": 1200,
"Quantity": 10,
"Discount": 0,
"Total_price":12000,
"Paid_amount":12000},
"YearMembers_Ribbons":{
"price": 110,
"Quantity": 0,
"Discount": 0,
"Total_price":1100,
"Paid_amount":1100}
}
self.grid = QtGui.QGridLayout(self)
hbox = QtGui.QHBoxLayout()
self.clbtn = QtGui.QPushButton('close')
self.clbtn.clicked.connect(self.close)
self.lab = QtGui.QLabel("orders")
hbox.addWidget(self.lab,alignment = QtCore.Qt.AlignCenter)
hbox.addStretch()
hbox.addWidget(self.clbtn,alignment = QtCore.Qt.AlignRight)
self.grid.addLayout(hbox,0,0)
self.line = QtGui.QFrame(frameShape=QtGui.QFrame.HLine)
self.grid.addWidget(self.line,1,0)
self.main_hbox = QtGui.QHBoxLayout()
self.scroll = QtGui.QScrollArea()
self.show()
self.VBox = QtGui.QVBoxLayout()
self.Date = QtGui.QLabel("25-2-2018",objectName="small",alignment = QtCore.Qt.AlignRight)
self.v_city = QtGui.QLabel("bangalore",alignment = QtCore.Qt.AlignCenter)
self.v_state = QtGui.QLabel("karnataka",alignment = QtCore.Qt.AlignCenter)
self.v_pincode = QtGui.QLabel("560003",alignment = QtCore.Qt.AlignCenter)
self.v_country = QtGui.QLabel("India",alignment = QtCore.Qt.AlignCenter)
self.VBox.addWidget(self.Date)
self.VBox.addWidget(self.v_city)
self.VBox.addWidget(self.v_state)
self.VBox.addWidget(self.v_pincode)
self.VBox.addWidget(self.v_country)
self.main_hbox.addLayout(self.VBox)
self.main_hbox.addWidget(self.scroll)
self.grid.addLayout(self.main_hbox,2,0)
w2 = QtGui.QWidget()
self.scroll.setWidget(w2)
grid1 = QtGui.QGridLayout(w2)
self.items_Vboxlay = QtGui.QVBoxLayout()
self.vbox2 = QtGui.QVBoxLayout()
for key, value in self.products_list.items():
keys = [ vk for vk in value.keys()]
values = [ vv for vv in value.values()]
self.item_label = QtGui.QLabel(str(key), objectName="small")
self.vbox2.addWidget(self.item_label)
self.hbox1 = QtGui.QHBoxLayout()
self.hbox2 = QtGui.QHBoxLayout()
self.price = QtGui.QLabel(keys[1] + ": " + u'\u20B9 ' +str(values[1]))
self.qnty = QtGui.QLabel(keys[3] + ": " + str(values[3]))
self.discount = QtGui.QLabel(keys[0] + ": " + u'\u20B9 ' + str(values[0]))
self.totalprice = QtGui.QLabel(keys[2] + ": " + u'\u20B9 ' + str(values[2]))
self.status = QtGui.QLabel("Status" + ": "+ "Created")
self.ref_amount = QtGui.QLabel("Refund Amount"+": "+ "0")
self.ref_status = QtGui.QLabel("Refund Status"+": "+ "False")
self.hbox1.addWidget(self.price)
self.hbox1.addWidget(self.qnty)
self.hbox1.addWidget(self.discount)
self.hbox1.addWidget(self.totalprice)
self.hbox2.addWidget(self.status)
self.hbox2.addWidget(self.ref_amount)
self.hbox2.addWidget(self.ref_status)
self.line4 = QtGui.QFrame()
self.line4.setFrameShape(QtGui.QFrame.HLine)
self.vbox2.addLayout(self.hbox1)
self.vbox2.addLayout(self.hbox2)
self.vbox2.addWidget(self.line4)
self.items_Vboxlay.addLayout(self.vbox2)
grid1.addLayout(self.items_Vboxlay,0,0)
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show()
ex.resize(500,300)
sys.exit(app.exec_())
if __name__ == '__main__':
main()
When a widget is set in a ScrollArea the size it uses is that of the widget at that moment, in your case it does not have any size so the widget will have size 0, 0 and although you add child widgets through a QScrollArea layout, it does not will take into account, so for QScrollArea to monitor the size you must enable the widgetResizable property:
self.scroll = QtGui.QScrollArea(widgetResizable=True)
Right now through reading and asking questions I have gotten to a point where I can display the numerical values on LCDs, but now would like to make a graph.
In the Picture below there is a picture that I am going to have as a backdrop for the graph. For a Dyno the important information that is gathered is Torque and HorsePower. These I have being calculated with my Python 3.5 Code and the data is being gathered by using an arduino.
For my graph I actually want to plot two lines at the same time as the data comes in. I would like to plot both the Torque and the HorsePower at the same time. Both of those vs the time that the Dyno is being used. This however might be hard since they need to be plotted with different y-axis. From what I have been reading using pyqtGraph is the best option for the job but due to my in experience with this kind of work I really don't know how to do it.
Below is my code that I have tried to run based on some of the things I have found. Running it does not error out my code, however It also does not interact with the graph area. I tried to get it to work in a similar fashion that the LCDs work in, but even still I don't have anything working.
"""
SCSU DYNO GUI PROGRAM
created 10/20/2017
"""
import sys
import time
import csv
import numpy as np
import warnings
import serial
import serial.tools.list_ports
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread,QTimer, pyqtSignal
from PyQt5.QtWidgets import QMessageBox,QWidget, QApplication
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import random
from DynoTest1 import Ui_DynoTest1
__author__ = 'Matt Munn'
class GetData(QThread):
dataChanged = pyqtSignal(float, float, float, float, float, float, float, float)
#Distance = 0.5 #This is dependent on the lever arm.
def __init__(self, parent=None):
QThread.__init__(self, parent)
arduino_ports = [ # automatically searches for an Arduino and selects the port it's on
p.device
for p in serial.tools.list_ports.comports()
if 'Arduino' in p.description
]
if not arduino_ports:
raise IOError("No Arduino found - is it plugged in? If so, restart computer.")
if len(arduino_ports) > 1:
warnings.warn('Multiple Arduinos found - using the first')
self.Arduino = serial.Serial(arduino_ports[0], 9600, timeout=1)
def __del__(self): # part of the standard format of a QThread
self.wait()
def run(self): # also a required QThread function, the working part
self.Arduino.close()
self.Arduino.open()
self.Arduino.flush()
self.Arduino.reset_input_buffer()
start_time = time.time()
Distance = 0.5 #This is dependent on the lever arm.
Max_RPM = 0
Max_HorsePower = 0
Max_Torque = 0
while True:
while self.Arduino.inWaiting() == 0:
pass
try:
data = self.Arduino.readline()
dataarray = data.decode().rstrip().split(',')
self.Arduino.reset_input_buffer()
Force = round(float(dataarray[0]), 3)
RPM = round(float(dataarray[1]), 3)
if Max_RPM < RPM:
Max_RPM = RPM
Torque = round(Force * Distance, 3)
if Max_Torque < Torque:
Max_Torque = Torque
HorsePower = round(Torque * RPM / 5252, 3)
if Max_HorsePower < HorsePower:
Max_HorsePower = HorsePower
Run_Time = round(time.time() - start_time, 3)
print(Force, 'Grams', ",", RPM, 'RPMs', ",", Torque, "ft-lbs", ",", HorsePower, "hp", Run_Time,
"Time Elasped")
self.dataChanged.emit(Force, RPM, Max_RPM, Torque, Max_Torque, HorsePower, Max_HorsePower, Run_Time)
except (KeyboardInterrupt, SystemExit, IndexError, ValueError):
pass
class GUI(QWidget, Ui_DynoTest1):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setupUi(self)
self.thread = GetData(self)
self.thread.dataChanged.connect(self.onDataChanged)
self.thread.start()
"""
layout = QtGui.QHBoxLayout()
self.plot = pg.PlotWidget()
layout.addWidget(self.plot)
self.setLayout(layout)
def plotter(self):
self.data = [0]
self.curve = self.plot.getPlotItem().plot()
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.updater)
self.timer.start(0)
def updater(self):
self.data.append(self.data[-1]+0.2*(0.5-random.random()))
self.curve.setData(self.data)
"""
def onDataChanged(self, Force, RPM, Max_RPM, Torque,Max_Torque, HorsePower, Max_HorsePower, Run_Time):
self.lcdNumber.display(Max_RPM)
self.lcdNumber_2.display(Max_Torque)
self.lcdNumber_3.display(Max_HorsePower)
self.lcdNumber_4.display(RPM)
self.lcdNumber_5.display(Torque)
self.lcdNumber_6.display(HorsePower)
self.lcdNumber_7.display(Run_Time)
#self.graphicsView.display(Tourque,Run_Time)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
Dyno = GUI()
Dyno.show()
sys.exit(app.exec_())
This is the code generated by the QTDesigner.
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'dynotest1.ui'
#
# Created by: PyQt5 UI code generator 5.9
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_DynoTest1(object):
def setupUi(self, DynoTest1):
DynoTest1.setObjectName("DynoTest1")
DynoTest1.resize(1001, 695)
self.verticalLayout_4 = QtWidgets.QVBoxLayout(DynoTest1)
self.verticalLayout_4.setObjectName("verticalLayout_4")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout_3 = QtWidgets.QVBoxLayout()
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.pushButton_2 = QtWidgets.QPushButton(DynoTest1)
self.pushButton_2.setObjectName("pushButton_2")
self.gridLayout.addWidget(self.pushButton_2, 1, 0, 1, 1)
self.pushButton_4 = QtWidgets.QPushButton(DynoTest1)
self.pushButton_4.setObjectName("pushButton_4")
self.gridLayout.addWidget(self.pushButton_4, 1, 1, 1, 1)
self.pushButton_3 = QtWidgets.QPushButton(DynoTest1)
self.pushButton_3.setObjectName("pushButton_3")
self.gridLayout.addWidget(self.pushButton_3, 0, 1, 1, 1)
self.pushButton = QtWidgets.QPushButton(DynoTest1)
self.pushButton.setObjectName("pushButton")
self.gridLayout.addWidget(self.pushButton, 0, 0, 1, 1)
self.verticalLayout_3.addLayout(self.gridLayout)
self.label_3 = QtWidgets.QLabel(DynoTest1)
self.label_3.setObjectName("label_3")
self.verticalLayout_3.addWidget(self.label_3)
self.label_2 = QtWidgets.QLabel(DynoTest1)
self.label_2.setObjectName("label_2")
self.verticalLayout_3.addWidget(self.label_2)
self.label = QtWidgets.QLabel(DynoTest1)
self.label.setObjectName("label")
self.verticalLayout_3.addWidget(self.label)
self.horizontalLayout.addLayout(self.verticalLayout_3)
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.label_5 = QtWidgets.QLabel(DynoTest1)
self.label_5.setObjectName("label_5")
self.verticalLayout.addWidget(self.label_5)
self.lcdNumber_4 = QtWidgets.QLCDNumber(DynoTest1)
self.lcdNumber_4.setFrameShape(QtWidgets.QFrame.Box)
self.lcdNumber_4.setFrameShadow(QtWidgets.QFrame.Raised)
self.lcdNumber_4.setLineWidth(1)
self.lcdNumber_4.setSmallDecimalPoint(True)
self.lcdNumber_4.setDigitCount(5)
self.lcdNumber_4.setMode(QtWidgets.QLCDNumber.Dec)
self.lcdNumber_4.setSegmentStyle(QtWidgets.QLCDNumber.Filled)
self.lcdNumber_4.setProperty("value", 0.0)
self.lcdNumber_4.setObjectName("lcdNumber_4")
self.verticalLayout.addWidget(self.lcdNumber_4)
self.lcdNumber_5 = QtWidgets.QLCDNumber(DynoTest1)
font = QtGui.QFont()
font.setBold(False)
font.setWeight(50)
self.lcdNumber_5.setFont(font)
self.lcdNumber_5.setSmallDecimalPoint(True)
self.lcdNumber_5.setObjectName("lcdNumber_5")
self.verticalLayout.addWidget(self.lcdNumber_5)
self.lcdNumber_6 = QtWidgets.QLCDNumber(DynoTest1)
self.lcdNumber_6.setSmallDecimalPoint(True)
self.lcdNumber_6.setObjectName("lcdNumber_6")
self.verticalLayout.addWidget(self.lcdNumber_6)
self.horizontalLayout.addLayout(self.verticalLayout)
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.label_6 = QtWidgets.QLabel(DynoTest1)
self.label_6.setObjectName("label_6")
self.verticalLayout_2.addWidget(self.label_6)
self.lcdNumber = QtWidgets.QLCDNumber(DynoTest1)
self.lcdNumber.setSmallDecimalPoint(True)
self.lcdNumber.setObjectName("lcdNumber")
self.verticalLayout_2.addWidget(self.lcdNumber)
self.lcdNumber_2 = QtWidgets.QLCDNumber(DynoTest1)
self.lcdNumber_2.setSmallDecimalPoint(True)
self.lcdNumber_2.setObjectName("lcdNumber_2")
self.verticalLayout_2.addWidget(self.lcdNumber_2)
self.lcdNumber_3 = QtWidgets.QLCDNumber(DynoTest1)
self.lcdNumber_3.setSmallDecimalPoint(True)
self.lcdNumber_3.setObjectName("lcdNumber_3")
self.verticalLayout_2.addWidget(self.lcdNumber_3)
self.horizontalLayout.addLayout(self.verticalLayout_2)
self.horizontalLayout_2.addLayout(self.horizontalLayout)
self.verticalLayout_5 = QtWidgets.QVBoxLayout()
self.verticalLayout_5.setObjectName("verticalLayout_5")
self.label_7 = QtWidgets.QLabel(DynoTest1)
self.label_7.setObjectName("label_7")
self.verticalLayout_5.addWidget(self.label_7)
self.lcdNumber_7 = QtWidgets.QLCDNumber(DynoTest1)
self.lcdNumber_7.setObjectName("lcdNumber_7")
self.verticalLayout_5.addWidget(self.lcdNumber_7)
self.horizontalLayout_2.addLayout(self.verticalLayout_5)
self.verticalLayout_4.addLayout(self.horizontalLayout_2)
self.graphicsView = QtWidgets.QGraphicsView(DynoTest1)
self.graphicsView.setStyleSheet("border-image: url(:/newPrefix/husky_head5.png);")
self.graphicsView.setLineWidth(1)
self.graphicsView.setObjectName("graphicsView")
self.verticalLayout_4.addWidget(self.graphicsView)
self.retranslateUi(DynoTest1)
QtCore.QMetaObject.connectSlotsByName(DynoTest1)
def retranslateUi(self, DynoTest1):
_translate = QtCore.QCoreApplication.translate
DynoTest1.setWindowTitle(_translate("DynoTest1", "DynoTest1"))
self.pushButton_2.setText(_translate("DynoTest1", "Pause"))
self.pushButton_4.setText(_translate("DynoTest1", "Print"))
self.pushButton_3.setText(_translate("DynoTest1", "Stop"))
self.pushButton.setText(_translate("DynoTest1", "Start"))
self.label_3.setText(_translate("DynoTest1", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">RPMs</span></p></body></html>"))
self.label_2.setText(_translate("DynoTest1", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">Torque (ft-lbs)</span></p></body></html>"))
self.label.setText(_translate("DynoTest1", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">Horse Power</span></p></body></html>"))
self.label_5.setText(_translate("DynoTest1", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">Now</span></p></body></html>"))
self.label_6.setText(_translate("DynoTest1", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">Max</span></p></body></html>"))
self.label_7.setText(_translate("DynoTest1", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">Run Time</span></p><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">(Seconds)</span></p></body></html>"))
import Resource_rc
Picture of the GUI
The first thing is to add the PlotWidget to the GUI. For this we use QGraphicsView (in fact any widget can be used), in the QGraphicsView we add a layout, and in this layout we add the PlotWidget.
layout = QHBoxLayout()
self.plot = pg.PlotWidget()
layout.addWidget(self.plot)
self.graphicsView.setLayout(layout)
Then the items are created, and as you wish to have 2 axes and in the same plot we take as an example the code found in the following link.
In the example you wanted to use, use a timer to update the data, but in this case that clock must be reading data for it every time the onDataChanged method is called. To obtain a view, a procedure has been created to only store and display the last 50 elements.
Code:
class GUI(QWidget, Ui_DynoTest1):
def __init__(self, parent=None):
[...]
self.thread.start()
self.torque = []
self.horse_power = []
layout = QHBoxLayout()
self.plot = pg.PlotWidget()
layout.addWidget(self.plot)
self.graphicsView.setLayout(layout)
self.p1 = self.plot.plotItem
self.p1.setLabels(left='Torque')
self.TorqueCurve = self.p1.plot()
self.TorqueCurve.setPen(pg.mkPen(color="#ff0000", width=2))
self.p2 = pg.ViewBox()
self.HorsePowerCurve = pg.PlotCurveItem()
self.HorsePowerCurve.setPen(pg.mkPen(QColor(0, 255, 0)), width=2)
self.p2.addItem(self.HorsePowerCurve)
self.p1.scene().addItem(self.p2)
self.p1.showAxis('right')
self.p1.getAxis('right').setLabel('HorsePower', color='#0000ff')
self.p1.getAxis('right').linkToView(self.p2)
self.p1.vb.sigResized.connect(self.updateViews)
def updateViews(self):
self.p2.setGeometry(self.p1.vb.sceneBoundingRect())
self.p2.linkedViewChanged(self.p1.vb, self.p2.XAxis)
def onDataChanged(self, Force, RPM, Max_RPM, Torque, Max_Torque, HorsePower, Max_HorsePower, Run_Time):
[...]
if len(self.torque) < 50:
self.torque.append(Torque)
else:
self.torque = self.torque[1:] + [Torque]
if len(self.horse_power) < 50:
self.horse_power.append(HorsePower)
else:
self.horse_power = self.horse_power[1:] + [HorsePower]
self.TorqueCurve.setData(self.torque)
self.HorsePowerCurve.setData(self.horse_power)
self.updateViews()