Related
The following code creates 7 tabs each from a different tab class. When it runs, all tabs are created and it opens with tab 1 selected. Once another tab is clicked, Tab 1 can never be opened again. Tab 2 sometimes can be opened, but most of the time not. All the other tabs can be opened at any time. Can any anyone tell me what I am doing wrong?
If I use a single class, create the different creation methods from within this class, and then call each method everything works.
The reason I want to use classes for the tabs is two fold. 1) there will be 10 tabs and each tab will have lots of widgets causing a very long file and 2) I want to be able to use Native Language Services (NLS).
import sys
from PyQt5.QtCore import (QMetaObject )
from PyQt5.QtWidgets import (QPushButton, QMainWindow,
QHBoxLayout, QApplication, QTabWidget,
QMenuBar, QStatusBar)
from Tab1 import *
from Tab2 import *
from Tab3 import *
class Ui_NFPCinput(QWidget):
def __init__(self):
super().__init__()
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1000, 1000)
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayoutWidget = QWidget(self.centralwidget)
self.horizontalLayoutWidget.setGeometry(QRect(0, 0, 990, 800))
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
self.horizontalLayout = QHBoxLayout(self.horizontalLayoutWidget)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.horizontalLayoutWidget_2 = QWidget(self.centralwidget)
self.horizontalLayoutWidget_2.setGeometry(QRect(300, 930, 641, 41))
self.horizontalLayoutWidget_2.setObjectName("horizontalLayoutWidget_2")
self.horizontalLayout_2 = QHBoxLayout(self.horizontalLayoutWidget_2)
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.GetFile = QPushButton(self.horizontalLayoutWidget_2)
self.GetFile.setObjectName("GetFile")
self.horizontalLayout_2.addWidget(self.GetFile)
self.CancelButton = QPushButton(self.horizontalLayoutWidget_2)
self.CancelButton.setObjectName("CancelButton")
self.horizontalLayout_2.addWidget(self.CancelButton)
self.OkButton = QPushButton(self.horizontalLayoutWidget_2)
self.OkButton.setObjectName("OkButton")
self.horizontalLayout_2.addWidget(self.OkButton)
self.tabWidget = QTabWidget(self.centralwidget)
self.tabWidget.setGeometry(QRect(10, 10, 980, 900))
self.tabWidget.setObjectName("tabWidget")
self.tab0 = Tab1(self.tabWidget)
self.tabWidget.addTab(self.tab0.getTab(), "")
self.tab1 = Tab2(self.tabWidget)
self.tabWidget.addTab(self.tab1.getTab(), "")
self.tab2 = Tab3(self.tabWidget)
self.tabWidget.addTab(self.tab2.getTab(), "")
self.tab3 = Tab1(self.tabWidget)
self.tabWidget.addTab(self.tab3.getTab(), "")
self.tab4 = Tab2(self.tabWidget)
self.tabWidget.addTab(self.tab4.getTab(), "")
self.tab5 = Tab3(self.tabWidget)
self.tabWidget.addTab(self.tab5.getTab(), "")
self.tab6 = Tab1(self.tabWidget)
self.tabWidget.addTab(self.tab6.getTab(), "")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(MainWindow)
self.menubar.setGeometry(QRect(0, 0, 649, 27))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Tabs Test"))
self.CancelButton.setText(_translate("MainWindow", "OK"))
self.OkButton.setText(_translate("MainWindow", "Cancel"))
self.GetFile.setText(_translate("MainWindow", "Test"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab0.getTab()), _translate("MainWindow", "Tab 0"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab1.getTab()), _translate("MainWindow", "Tab 1"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab2.getTab()), _translate("MainWindow", "Tab 2"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab3.getTab()), _translate("MainWindow", "Tab 3"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab4.getTab()), _translate("MainWindow", "Tab 4"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab5.getTab()), _translate("MainWindow", "Tab 5"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab6.getTab()), _translate("MainWindow", "Tab 6"))
if __name__ == "__main__":
app = QApplication(sys.argv)
MainWindow = QMainWindow()
ui = Ui_NFPCinput()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
The template for the tab classes, just change the tab number
from PyQt5.QtCore import QRect, QCoreApplication
from PyQt5.QtWidgets import QWidget, QLabel
class Tab1(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
self.tab = QWidget()
self.tab.setObjectName("Tab1")
self.label = QLabel(self.tab)
self.label.setGeometry(QRect(20, 10, 200, 19))
self.label.setObjectName("label")
self.label.setText("")
self.retranslateUi()
def getTab(self):
return self.tab
def retranslateUi(self):
_translate = QCoreApplication.translate
self.label.setText(_translate( "MainTab","This is Object 1"))
The problem is in your Tab1. You've got an extra level of widgets.
from PyQt5.QtCore import QRect, QCoreApplication
from PyQt5.QtWidgets import QWidget, QLabel
class Tab1(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
# self.tab = QWidget()
# self.tab.setObjectName("Tab1")
self.setObjectName("Tab1")
# self.label = QLabel(self.tab)
self.label = QLabel(self)
self.label.setGeometry(QRect(20, 10, 200, 19))
self.label.setObjectName("label")
self.label.setText("")
self.retranslateUi()
def getTab(self):
# return self.tab
return self
def retranslateUi(self):
_translate = QCoreApplication.translate
self.label.setText(_translate( "MainTab","This is Object 1"))
Correction: Changed the line
super(QWidget, self).__init__(parent)
to
super(QWidget, self).__init__()
This worked.
I am trying to build a simple internet speed test app using pyqt5
I am a beginner and trying to build small apps to learn GUI basics So here is the code whenever i try to change label text from my thread function is says that self has no member named label_7. ignore the print statements i was just using them for debugging
def Update_values(self,MainWindow):
_translate = QtCore.QCoreApplication.translate
self.label_7.setText(_translate("MainWindow", "Download Speed : " + str(down)))
at the upper part of code i got error
Thank you in advance
from PyQt5 import QtCore, QtGui, QtWidgets
import speedtest as st
speed_test = st.Speedtest()
download = speed_test.download()
val = 0
val1 = 0
val3 = 0
down = 0
up = 0
pin = 0
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(331, 307)
font = QtGui.QFont()
font.setFamily("Lucida Sans Unicode")
MainWindow.setFont(font)
MainWindow.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
MainWindow.setMouseTracking(False)
MainWindow.setTabletTracking(False)
MainWindow.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
MainWindow.setDocumentMode(False)
MainWindow.setTabShape(QtWidgets.QTabWidget.Triangular)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.label = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Comic Sans MS")
font.setPointSize(16)
self.label.setFont(font)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 3)
self.line_2 = QtWidgets.QFrame(self.centralwidget)
self.line_2.setFrameShape(QtWidgets.QFrame.HLine)
self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
self.line_2.setObjectName("line_2")
self.gridLayout.addWidget(self.line_2, 1, 0, 1, 3)
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 2)
self.label_4 = QtWidgets.QLabel(self.centralwidget)
self.label_4.setFrameShape(QtWidgets.QFrame.NoFrame)
self.label_4.setObjectName("label_4")
self.gridLayout.addWidget(self.label_4, 3, 0, 1, 2)
self.label_3 = QtWidgets.QLabel(self.centralwidget)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 4, 0, 1, 2)
self.label_7 = QtWidgets.QLabel(self.centralwidget)
self.label_7.setObjectName("label_7")
self.gridLayout.addWidget(self.label_7, 5, 0, 1, 2)
self.label_8 = QtWidgets.QLabel(self.centralwidget)
self.label_8.setObjectName("label_8")
self.gridLayout.addWidget(self.label_8, 6, 0, 1, 1)
self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
self.progressBar.setProperty("value", 24)
self.progressBar.setTextVisible(False)
self.progressBar.setObjectName("progressBar")
self.gridLayout.addWidget(self.progressBar, 7, 0, 1, 3)
self.check1 = QtWidgets.QCheckBox(self.centralwidget)
self.check1.setObjectName("check1")
self.check1.stateChanged.connect(self.check_1)
self.gridLayout.addWidget(self.check1, 8, 0, 1, 1)
self.check2 = QtWidgets.QCheckBox(self.centralwidget)
self.check2.setObjectName("check2")
self.check2.stateChanged.connect(self.check_2)
self.gridLayout.addWidget(self.check2, 8, 1, 1, 1)
self.check3 = QtWidgets.QCheckBox(self.centralwidget)
self.check3.setObjectName("check3")
self.check3.stateChanged.connect(self.check_3)
self.gridLayout.addWidget(self.check3, 8, 2, 1, 1)
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setObjectName("pushButton")
self.pushButton.clicked.connect(self.start_test)
self.gridLayout.addWidget(self.pushButton, 9, 0, 1, 3)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 331, 22))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
self.menuAbout = QtWidgets.QMenu(self.menubar)
self.menuAbout.setObjectName("menuAbout")
MainWindow.setMenuBar(self.menubar)
self.actionSave_Results = QtWidgets.QAction(MainWindow)
self.actionSave_Results.setCheckable(False)
self.actionSave_Results.setChecked(False)
self.actionSave_Results.setObjectName("actionSave_Results")
self.actionChange_Save_Directory = QtWidgets.QAction(MainWindow)
self.actionChange_Save_Directory.setObjectName("actionChange_Save_Directory")
self.actionDeveloper = QtWidgets.QAction(MainWindow)
self.actionDeveloper.setObjectName("actionDeveloper")
self.menuFile.addAction(self.actionSave_Results)
self.menuFile.addAction(self.actionChange_Save_Directory)
self.menuAbout.addAction(self.actionDeveloper)
self.menubar.addAction(self.menuFile.menuAction())
self.menubar.addAction(self.menuAbout.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Internet Speed Test"))
self.label.setText(_translate("MainWindow", "Internet Speed Test By FATE"))
self.label_2.setText(_translate("MainWindow", "Status : Connected"))
self.label_4.setText(_translate("MainWindow", "Ping : --"))
self.label_3.setText(_translate("MainWindow", "Upload Speed : --"))
self.label_7.setText(_translate("MainWindow", "Download Speed : --"))
self.label_8.setText(_translate("MainWindow", "Progress :"))
self.check1.setText(_translate("MainWindow", "Download"))
self.check2.setText(_translate("MainWindow", "Upload"))
self.check3.setText(_translate("MainWindow", "Ping"))
self.pushButton.setText(_translate("MainWindow", "Start"))
self.menuFile.setTitle(_translate("MainWindow", "File"))
self.menuAbout.setTitle(_translate("MainWindow", "About"))
self.actionSave_Results.setText(_translate("MainWindow", "Save Results"))
self.actionChange_Save_Directory.setText(_translate("MainWindow", "Change Save Directory"))
self.actionDeveloper.setText(_translate("MainWindow", "Developer"))
self.Update_values(MainWindow)
def Update_values(self,MainWindow):
_translate = QtCore.QCoreApplication.translate
self.label_7.setText(_translate("MainWindow", "Download Speed : " + str(down)))
# self.label_7.setText(_translate("MainWindow", "Download Speed : 10"))
print(down)
print(up)
print(pin)
def check_1(self, state):
global val
print(val)
if state != self.check1.isChecked():
val += 1
print("YESH "+ str(val))
else:
val -= 1
print("NO" + str(val))
def check_2(self, state):
global val1
print(val1)
if state != self.check1.isChecked():
val1 += 1
print("YESH "+ str(val1))
else:
val1 -= 1
print("NO" + str(val1))
def check_3(self, state):
global val3
print(val3)
if state != self.check1.isChecked():
val3 += 1
print("YESH "+ str(val3))
else:
val3 -= 1
print("NO" + str(val3))
def start_test(self):
self.threadclass = Thread()
self.threadclass.start()
class Thread(QtCore.QThread,Ui_MainWindow):
def __init__(self,parent = None):
super(Thread, self).__init__(parent)
def run(self):
if val == 1:
download = speed_test.download()
download_mbs = round(download / (10**6), 2)
global down
down = download_mbs
self.Update_values(Ui_MainWindow)
if val1 == 1:
upload = speed_test.upload()
upload_mbs = round(upload / (10**6), 2)
global up
up = upload_mbs
if val3 == 1:
ping = speed_test.results.ping
global pin
pin = ping
print("DONE")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
First of all, you should not modify the code generated by Qt Designer, so in my next solution you must regenerate the .py generated by pyuic and call it gui.py: python -m pyuic5 your_ui.ui -o gui.py.
Another error you have is that you should not update the GUI from another thread, nor use global variables since they are prone to generating silent errors, instead you should use the signals as shown below:
from enum import Flag, auto
import threading
from PyQt5 import QtCore, QtGui, QtWidgets
import speedtest
from gui import Ui_MainWindow
class Task(Flag):
NONE = auto()
DOWNLOAD = auto()
UPLOAD = auto()
PING = auto()
class SpeedtestWrapper(QtCore.QObject):
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
downloaded = QtCore.pyqtSignal(float)
uploaded = QtCore.pyqtSignal(float)
pinged = QtCore.pyqtSignal(float)
def start(self, flag):
threading.Thread(target=self._execute, args=(flag,), daemon=True).start()
def _execute(self, flag):
self.started.emit()
speed_test = speedtest.Speedtest()
if flag & Task.DOWNLOAD:
download = speed_test.download()
download_mbs = round(download / (10 ** 6), 2)
self.downloaded.emit(download_mbs)
if flag & Task.DOWNLOAD:
upload = speed_test.upload()
upload_mbs = round(upload / (10 ** 6), 2)
self.uploaded.emit(upload_mbs)
if flag & Task.DOWNLOAD:
ping = speed_test.results.ping
self.pinged.emit(ping)
self.finished.emit()
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self._flag = Task.NONE
self.speed_wrapper = SpeedtestWrapper()
self.speed_wrapper.started.connect(self.on_started)
self.speed_wrapper.finished.connect(self.on_finished)
self.speed_wrapper.downloaded.connect(self.on_downloaded)
self.speed_wrapper.uploaded.connect(self.on_uploaded)
self.speed_wrapper.pinged.connect(self.on_pinged)
#QtCore.pyqtSlot()
def start_test(self):
if self._flag != Task.NONE:
self.speed_wrapper.start(self._flag)
#QtCore.pyqtSlot(int)
def check_1(self, state):
if state:
self._flag |= Task.DOWNLOAD
else:
self._flag &= ~Task.DOWNLOAD
#QtCore.pyqtSlot(int)
def check_2(self, state):
if state:
self._flag |= Task.UPLOAD
else:
self._flag &= ~Task.UPLOAD
#QtCore.pyqtSlot(int)
def check_3(self, state):
if state:
self._flag |= Task.PING
else:
self._flag &= ~Task.PING
#QtCore.pyqtSlot()
def on_started(self):
self.label_7.setText(self.tr("Download Speed: --"))
self.label_3.setText(self.tr("Upload Speed: --"))
self.label_4.setText(self.tr("Ping Speed: --"))
self.pushButton.setEnabled(False)
#QtCore.pyqtSlot()
def on_finished(self):
self.pushButton.setEnabled(True)
#QtCore.pyqtSlot(float)
def on_downloaded(self, download):
self.label_7.setText(self.tr("Download Speed: %f" % download))
#QtCore.pyqtSlot(float)
def on_uploaded(self, upload):
self.label_3.setText(self.tr("Upload Speed: %f" % upload))
#QtCore.pyqtSlot(float)
def on_pinged(self, ping):
self.label_4.setText(self.tr("Ping Speed: %f" % ping))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
This question already has answers here:
Qt 4: Move window without title bar
(2 answers)
Closed 2 years ago.
I am trying to make an image viewer in PyQt5 with Python.
So far I have the functionality I want at the moment, this is a matter of styling the GUI how I would like it.
It looks almost how I want it.
I struggled to get that transparentish background, but managed to by setting windowflags to FramelesswindowHint. Unfortunately, now I don't have a menubar to close the application if I want to and drag the window around. I figure I will have to craft my own bar if I want to style it in a way that suits my background, which is fine, adding an X button to close the window shouldn't be too much of an issue.
My question is, how do I make it so I can drag the window around? I could make a rectangle widget and position it at the top with my buttons, but how do I get the whole window to move if the user clicks and drags it? I know similar questions are around, but I'm not sure how to make click and drag functions yet on objects in PyQt5 and it seems they use different layout strategies so I'm finding them confusing.
Here is my code:
from PyQt5 import QtCore, QtGui, QtWidgets
import os
class Ui_MainWindow(object):
def __init__(self):
cwd = r"C:\Users\chees\PycharmProjects\PYQT5GUI\images"
self.imagelist = []
self.imagepaths = []
self.imagecount = 0
for a, b, c in os.walk(cwd):
self.imagelist = c
for i in c:
self.imagepaths.append(a + "\\" + i)
print(self.imagepaths)
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowModality(QtCore.Qt.NonModal)
MainWindow.resize(661, 580)
MainWindow.setAttribute(QtCore.Qt.WA_TranslucentBackground)
MainWindow.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.b = QtWidgets.QWidget(self.centralwidget)
self.b.setGeometry(QtCore.QRect(0, 0, MainWindow.width(), MainWindow.height()))
self.b.setStyleSheet("background-color: rgba(0, 0, 0, 70%); border:1px; border-radius:25px;")
self.imageviewer = QtWidgets.QLabel(self.centralwidget)
self.imageviewer.setGeometry(QtCore.QRect(170, 60, 351, 321))
self.imageviewer.setText("")
self.imageviewer.setPixmap(QtGui.QPixmap("images/IMG1.jpg"))
self.imageviewer.setScaledContents(True)
self.imageviewer.setObjectName("imageviewer")
self.backward_button = QtWidgets.QPushButton(self.centralwidget)
self.backward_button.setGeometry(QtCore.QRect(50, 471, 120, 50))
self.backward_button.setObjectName("backward_button")
self.backward_button.clicked.connect(self.backward)
self.forward_button = QtWidgets.QPushButton(self.centralwidget)
self.forward_button.setGeometry(QtCore.QRect(510, 470, 120, 50))
self.forward_button.setObjectName("forward_button")
self.forward_button.clicked.connect(self.forward)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
self.statusbar.setStyleSheet("background-color: rgba(255,255,255, 40%)")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.changesize()
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.backward_button.setText(_translate("MainWindow", "<<"))
self.forward_button.setText(_translate("MainWindow", ">>"))
def changesize(self):
self.imageviewer.adjustSize()
if self.imageviewer.width() < 500:
MainWindow.resize(500, self.imageviewer.height() + 200)
self.b.resize(500, self.imageviewer.height() + 200)
self.imageviewer.move((500-self.imageviewer.width())//2, 55)
else:
MainWindow.resize((self.imageviewer.width() + self.imageviewer.width() // 8), (self.imageviewer.height() + 200))
self.b.resize((self.imageviewer.width() + self.imageviewer.width() // 8),
(self.imageviewer.height() + 200))
self.imageviewer.move(self.imageviewer.width() // 16, 55)
self.forward_button.move(MainWindow.width()-150,MainWindow.height()-80)
self.backward_button.move(30, MainWindow.height() - 80)
self.statusbar.showMessage(self.imagepaths[self.imagecount])
def flipmode(self):
self.imageviewer.setPixmap(QtGui.QPixmap("images\\" + self.imagelist[self.imagecount]))
self.changesize()
print(self.imageviewer.height(), self.imageviewer.width())
def forward(self):
self.imagecount += 1
if self.imagecount == len(self.imagelist):
self.imagecount = 0
self.flipmode()
def backward(self):
self.imagecount -= 1
if self.imagecount < 0:
self.imagecount = len(self.imagelist)-1
self.flipmode()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
print(ui.imagelist)
sys.exit(app.exec_())
Do not modify the code generated by Qt Designer but create another class that inherits
from the appropriate widget and use the initial class to fill it.
One of the ways to drag a window might look like this:
self._old_pos = None
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self._old_pos = event.pos()
def mouseReleaseEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self._old_pos = None
def mouseMoveEvent(self, event):
if not self._old_pos:
return
delta = event.pos() - self._old_pos
self.move(self.pos() + delta)
from PyQt5 import QtCore, QtGui, QtWidgets
import os
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowModality(QtCore.Qt.NonModal)
MainWindow.resize(661, 580)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.b = QtWidgets.QWidget(self.centralwidget)
self.b.setGeometry(QtCore.QRect(0, 0, MainWindow.width(), MainWindow.height()))
self.b.setStyleSheet("background-color: rgba(0, 0, 0, 70%); border:1px; border-radius:25px;")
self.imageviewer = QtWidgets.QLabel(self.centralwidget)
self.imageviewer.setGeometry(QtCore.QRect(170, 60, 351, 321))
self.imageviewer.setText("")
self.imageviewer.setPixmap(QtGui.QPixmap("images/IMG1.jpg"))
self.imageviewer.setScaledContents(True)
self.imageviewer.setObjectName("imageviewer")
self.backward_button = QtWidgets.QPushButton(self.centralwidget)
self.backward_button.setGeometry(QtCore.QRect(50, 471, 120, 50))
self.backward_button.setObjectName("backward_button")
self.backward_button.clicked.connect(self.backward)
self.forward_button = QtWidgets.QPushButton(self.centralwidget)
self.forward_button.setGeometry(QtCore.QRect(510, 470, 120, 50))
self.forward_button.setObjectName("forward_button")
self.forward_button.clicked.connect(self.forward)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
self.statusbar.setStyleSheet("background-color: rgba(255,255,255, 40%)")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.backward_button.setText(_translate("MainWindow", "<<"))
self.forward_button.setText(_translate("MainWindow", ">>"))
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
# cwd = r"C:\Users\chees\PycharmProjects\PYQT5GUI\images"
cwd = "D:/_Qt/__Qt/images"
self.imagelist = []
self.imagepaths = []
self.imagecount = 0
for a, b, c in os.walk(cwd):
self.imagelist = c
for i in c:
self.imagepaths.append(a + "\\" + i)
#print(self.imagepaths)
self.changesize()
#++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
self._old_pos = None
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self._old_pos = event.pos()
def mouseReleaseEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self._old_pos = None
def mouseMoveEvent(self, event):
if not self._old_pos:
return
delta = event.pos() - self._old_pos
self.move(self.pos() + delta)
# ++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
def changesize(self):
self.imageviewer.adjustSize()
if self.imageviewer.width() < 500:
self.resize(500, self.imageviewer.height() + 200)
self.b.resize(500, self.imageviewer.height() + 200)
self.imageviewer.move((500-self.imageviewer.width())//2, 55)
else:
self.resize((self.imageviewer.width() + self.imageviewer.width() // 8), (self.imageviewer.height() + 200))
self.b.resize((self.imageviewer.width() + self.imageviewer.width() // 8),
(self.imageviewer.height() + 200))
self.imageviewer.move(self.imageviewer.width() // 16, 55)
self.forward_button.move(self.width()-150, self.height()-80)
self.backward_button.move(30, self.height() - 80)
self.statusbar.showMessage(self.imagepaths[self.imagecount])
def flipmode(self):
self.imageviewer.setPixmap(QtGui.QPixmap("images\\" + self.imagelist[self.imagecount]))
self.changesize()
# print(self.imageviewer.height(), self.imageviewer.width())
def forward(self):
self.imagecount += 1
if self.imagecount == len(self.imagelist):
self.imagecount = 0
self.flipmode()
def backward(self):
self.imagecount -= 1
if self.imagecount < 0:
self.imagecount = len(self.imagelist)-1
self.flipmode()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
# MainWindow = QtWidgets.QMainWindow()
# ui = Ui_MainWindow()
# ui.setupUi(MainWindow)
# MainWindow.show()
w = MainWindow()
w.show()
# print(ui.imagelist)
sys.exit(app.exec_())
I want to build a program where we get updated data from interactive brokers (a popular online broker) and I want to update a plot in a simple pyqt5 interface.
The program sequence is the following:
We start the Ui_MainWindow interface. If we click on pushbutton2 we initiate a thread with the function GetDataBackground. This function uses the class GetDataand every time there is an update of the data to plot, the function tickPrice and tickSize is executed. In this step, I want to update the plot (for the moment it can be with random numbers like codded in the update_graph).
When I run the program it returns the error:
AttributeError: 'GetData' object has no attribute 'MplWidget'
Which seams that I do not have access to the main window.
The code is the following:
from PyQt5 import QtCore, QtGui, QtWidgets
from mplwidget import MplWidget
import threading
import sys
sys.path.insert(0, "/Users/nuno/Desktop/IB_API/source/pythonclient/")
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
from ibapi.ticktype import TickTypeEnum
import numpy as np
import sys
class GetData(EWrapper, EClient):
outrights = []
calendars = []
flies = []
def __init__(self):
EClient.__init__(self, self)
def error(self, reqId, errorCode, errorString):
print("Error: ", reqId, " ", errorCode, " ", errorString)
def tickPrice(self, reqId , tickType, price, attrib):
print("Tick Price. Ticker Id: ", reqId, "tickType: ", TickTypeEnum.to_str(tickType), " Price: ", price, end='\n')
self.outrights[reqId][TickTypeEnum.to_str(tickType)] = price
price = [x['DELAYED_LAST'] for x in self.outrights]
print('Push button')
self.testplot()
self.update_graph()
print(price)
def tickSize(self, reqId, tickType, size):
print("Tick Size. Ticker Id: ", reqId, "tickType: ", TickTypeEnum.to_str(tickType), 'Size: ', size)
self.outrights[reqId][TickTypeEnum.to_str(tickType)] = size
self.testplot()
def testplot(self):
print('Function correctly called')
def update_graph(self):
print('Push button')
x = np.random.rand(30)
y = np.random.rand(30)
self.MplWidget.canvas.axes.clear()
self.MplWidget.canvas.axes.plot(x, y)
self.MplWidget.canvas.axes.legend(('random'), loc='upper right')
self.MplWidget.canvas.draw()
def GetDataBackground():
"""
This function gets the data in the background.
:param PlotData:
:return:
"""
print('Interactive Brokers get data has started.')
app = GetData()
app.connect("127.0.0.1", 4002, 0)
print("serverVersion: {} connectionTime: {}".format(app.serverVersion(), app.twsConnectionTime()))
contract_list = ['GEZ0', 'GEH1', 'GEM1', 'GEU1', 'GEZ1', 'GEH2', 'GEM2', 'GEU2', 'GEZ2', 'GEH3', 'GEM3', 'GEU3',
'GEZ3', 'GEH4', 'GEM4', 'GEU4', 'GEZ4']
# This for loop generates a list of dictionaries that live inside the class TestApp
for i, contract in enumerate(contract_list):
temp_dict = {}
print(contract)
temp_dict['localSymbol'] = contract
temp_dict['tickerID'] = i
temp_dict['DELAYED_ASK'] = None
temp_dict['DELAYED_BID'] = None
temp_dict['DELAYED_OPEN'] = None
temp_dict['DELAYED_HIGH'] = None
temp_dict['DELAYED_LOW'] = None
temp_dict['DELAYED_CLOSE'] = None
temp_dict['DELAYED_ASK_SIZE'] = None
temp_dict['DELAYED_BID_SIZE'] = None
temp_dict['DELAYED_VOLUME'] = None
temp_dict['DELAYED_LAST'] = None
temp_dict['DELAYED_LAST_SIZE'] = None
app.outrights.append(temp_dict)
contracts = [Contract() for x in contract_list] # _
for i in range(len(contract_list)):
contracts[i].secType = 'FUT'
contracts[i].exchange = 'GLOBEX'
contracts[i].currency = 'USD'
contracts[i].localSymbol = contract_list[i]
app.reqMarketDataType(3)
for i in range(len(contract_list)):
print(contracts[i].localSymbol)
app.reqMktData(i, contracts[i], "", False, False, [])
app.run()
class Ui_MainWindow(GetData):
def __init__(self):
super().__init__()
def start_download(self):
download_info = threading.Thread(target = GetDataBackground)
download_info.start()
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1280, 1024)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(880, 80, 221, 32))
self.pushButton.setObjectName("pushButton")
self.pushButton2 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton2.setGeometry(QtCore.QRect(880, 45, 221, 32))
self.pushButton2.setObjectName("Get data")
self.MplWidget = MplWidget(self.centralwidget)
self.MplWidget.setGeometry(QtCore.QRect(49, 39, 771, 551))
self.MplWidget.setObjectName("MplWidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1148, 22))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.actionOpen = QtWidgets.QAction(MainWindow)
self.actionOpen.setObjectName("actionOpen")
self.actionSave = QtWidgets.QAction(MainWindow)
self.actionSave.setObjectName("actionSave")
self.actionClose = QtWidgets.QAction(MainWindow)
self.actionClose.setObjectName("actionClose")
self.actionSave_as = QtWidgets.QAction(MainWindow)
self.actionSave_as.setObjectName("actionSave_as")
self.menuFile.addSeparator()
self.menuFile.addAction(self.actionOpen)
self.menuFile.addAction(self.actionSave)
self.menuFile.addAction(self.actionSave_as)
self.menuFile.addSeparator()
self.menuFile.addAction(self.actionClose)
self.menubar.addAction(self.menuFile.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "PushButton"))
self.pushButton2.setText(_translate("MainWindow", "GetData"))
self.menuFile.setTitle(_translate("MainWindow", "File"))
self.actionOpen.setText(_translate("MainWindow", "Open..."))
self.actionSave.setText(_translate("MainWindow", "Save"))
self.actionClose.setText(_translate("MainWindow", "Close"))
self.actionSave_as.setText(_translate("MainWindow", "Save As..."))
self.pushButton.clicked.connect(self.update_graph)
self.pushButton2.clicked.connect(self.start_download)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Please refer to:
https://eli.thegreenplace.net/2009/01/20/matplotlib-with-pyqt-guis
This is an excellent example for matplotlib with PyQt GUIs
Refer here too for more detailed example:
https://github.com/eliben/code-for-blog/blob/master/2008/wx_mpl_dynamic_graph.py
I have a program with two QTreeView. When I press a button, I need to allow the user to select several elements, and when user press Escape, to transfer the selected elements to a waiting function, which will then pass to the handler function.
I've tried to use threads, gevent, and asyncio.
this function in main class, i run this function when i need get some files.
import sys
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import *
import ui
import exampleQTV
import asyncio
class PyMap(QMainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.select.clicked.connect(self.selectAction)
def selectAction(self):
self.getSomeFiles("Example", "Select some files, and press Escape", self.leftView)
def getSomeFiles(self, title, path, view):
# return QFileDialog.getOpenFileNames(self, title, path) ### older, and ugly variant
buttonReply = QMessageBox.information(self, "Information", "Select needed files",
QMessageBox.Ok)
loop = asyncio.get_event_loop()
tasks = [loop.create_task(view.getFiles())]
wait_tasks = asyncio.wait(tasks)
result = loop.run_until_complete(asyncio.gather(*tasks))
print (result)
# result = view.getFiles()
return result
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.rightView = exampleQTV.exampleQTV()
self.rightView.setObjectName("rightView")
self.gridLayout.addWidget(self.rightView, 1, 1, 1, 1)
self.leftView = exampleQTV.exampleQTV()
self.leftView.setObjectName("leftView")
self.gridLayout.addWidget(self.leftView, 1, 0, 1, 1)
self.select = QtWidgets.QPushButton(self.centralwidget)
self.select.setObjectName("select")
self.gridLayout.addWidget(self.select, 0, 0, 1, 2)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.select.setText(_translate("MainWindow", "Select"))
def main():
app = QtWidgets.QApplication(sys.argv)
window = PyMap()
window.show()
app.exec_()
if __name__ == '__main__':
main()
this functions in QTreeView's class
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from multiprocessing.pool import ThreadPool
import asyncio
class exampleQTV(QTreeView):
def __init__(self):
QTreeView.__init__(self)
self.model = QFileSystemModel()
self.model.setRootPath("/") # i'm on linux if you not change from / to for example D:\\
self.setModel(self.model)
self.eventCalled = False
self.requestForEscape = False
self.setColumnHidden(1, True)
self.setColumnHidden(2, True)
self.setColumnHidden(3, True)
def keyPressEvent(self, event):
if event.key() == Qt.Key_Escape:
self.eventCalled = false
def getFiles_thread(self):
while True:
if self.requestForEscape == True:
if self.eventCalled == False:
return self.selectedIndexes()
async def getFiles(self):
self.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection)
self.eventCalled = True
self.requestForEscape = True
pool = ThreadPool(processes=1)
self.printMessage(1)
async_result = pool.apply_async(self.getFiles_thread)
self.printMessage(2)
result = await async_result.get()
self.printMessage(3)
# ### Sorry if it not corrent, i'm just copied from doc
# tasks = [self.getFiles_thread()]
# loop = asyncio.get_event_loop()
# result = loop.run_until_complete(asyncio.gather(*tasks))
# task = [gevent.spawn(self.getFiles_thread(), 2)]
# result = gevent.joinall(task)
# result = await self.getFiles_thread()
self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
return result
def printMessage(self, message):
print(message)
output:
1
2
The tasks of the GUI such as the selection of items, listening to keyboard events, etc. do not need to be executed in another thread, nor in another process.
Your way of programming is procedural but in the GUI the paradigm of Event-driven Programming is used, in the case of Qt it is implemented through the signals, slot and events. Only tasks that synchronously consume a lot of time must be executed in another thread, for example I emulated the task of copying with QtCore.QThread.sleep(...).
Considering the above I have implemented the logic of enabling the selection, listen to the keyPressEvent, emit a signal with the selected indexes, and call the heavy function with the data.
main.py
import sys
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets
import exampleQTV
class PyMap(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.select.clicked.connect(self.selectAction)
self.leftView.selectedIndexesSignal.connect(
self.on_selectedIndexesSignal
)
thread = QtCore.QThread(self)
thread.start()
self.m_worker = Worker()
self.m_worker.moveToThread(thread)
#QtCore.pyqtSlot()
def selectAction(self):
buttonReply = QtWidgets.QMessageBox.information(
self,
"Information",
"Select needed files",
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel,
)
if buttonReply == QtWidgets.QMessageBox.Ok:
self.leftView.setEnableMultiSelection(True)
#QtCore.pyqtSlot(list)
def on_selectedIndexesSignal(self, indexes):
paths = []
for ix in indexes:
path = ix.data(QtWidgets.QFileSystemModel.FilePathRole)
paths.append(path)
print(paths)
wrapper = partial(self.m_worker.heavyTask, paths)
QtCore.QTimer.singleShot(0, wrapper)
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.rightView = exampleQTV.ExampleQTV()
self.rightView.setObjectName("rightView")
self.gridLayout.addWidget(self.rightView, 1, 1, 1, 1)
self.leftView = exampleQTV.ExampleQTV()
self.leftView.setObjectName("leftView")
self.gridLayout.addWidget(self.leftView, 1, 0, 1, 1)
self.select = QtWidgets.QPushButton(self.centralwidget)
self.select.setObjectName("select")
self.gridLayout.addWidget(self.select, 0, 0, 1, 2)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.select.setText(_translate("MainWindow", "Select"))
class Worker(QtCore.QObject):
#QtCore.pyqtSlot(list)
def heavyTask(self, paths):
print("started")
# emulate heavy task
QtCore.QThread.sleep(5)
print(paths)
print("finished")
def main():
app = QtWidgets.QApplication(sys.argv)
window = PyMap()
window.show()
app.exec_()
if __name__ == "__main__":
main()
exampleQTV.py
from PyQt5 import QtCore, QtGui, QtWidgets
class ExampleQTV(QtWidgets.QTreeView):
selectedIndexesSignal = QtCore.pyqtSignal(list)
def __init__(self, parent=None):
super(ExampleQTV, self).__init__(parent)
self.model = QtWidgets.QFileSystemModel(self)
self.model.setRootPath(QtCore.QDir.rootPath())
self.setModel(self.model)
for i in (1, 2, 3):
self.setColumnHidden(i, True)
self.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
self.expandAll()
def setEnableMultiSelection(self, enable):
self.setSelectionMode(
QtWidgets.QAbstractItemView.MultiSelection
if enable
else QtWidgets.QAbstractItemView.NoSelection
)
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Escape:
self.selectedIndexesSignal.emit(self.selectedIndexes())
self.selectionModel().clearSelection()
self.setEnableMultiSelection(False)
super(ExampleQTV, self).keyPressEvent(event)