How to show a pixmap in pyqt5 in __init__ - python

I have a simple Python application using PyQt5 that shall perform an update.
Currently I'm stuck directly within the __init__, when I add two pixmaps and a lineEdit whose text that I want to update during a calculation.
Whenever I use the main_window.change() the GUI is not shown until the change() is finished.
The pictures are not shown.
Without the change method it's showing the pics
Without change method GUI is shown correctly
If I add a QMessageBox into the for loop, the message is shown of course, but also the updated GUI becomes visible.
The message box updates the GUI
Adding a self.update() did not help.
class AcselStarter(QtWidgets.QMainWindow, Ui_ACSEL_Starter):
def __init__(self, parent=None):
super(AcselStarter, self).__init__(parent)
Ui_ACSEL_Starter.__init__(self)
self.setupUi(self)
pixmapAcsel = QPixmap('../fig/ACSEL.png')
self.labelAcsel.setPixmap(pixmapAcsel)
pixmapMubea = QPixmap('../fig/CAELogo_height60.png')
self.labelMubea.setPixmap(pixmapMubea)
self.lineEditProgress.setText(str(0.001))
def change(self):
for i in range(0, 100, 10):
self.lineEditProgress.setText(str(i))
# QtWidgets.QMessageBox.information(self, PROGRAMM_NAME, 'Replot', QtWidgets.QMessageBox.Ok)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
main_window = AcselStarter()
main_window.show()
time.sleep(5)
main_window.change()
sys.exit(app.exec_())
For completeness, here's my UI file from Qt Designer:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'UI_acsel_starter.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ACSEL_Starter(object):
def setupUi(self, ACSEL_Starter):
ACSEL_Starter.setObjectName("ACSEL_Starter")
ACSEL_Starter.resize(320, 180)
self.centralwidget = QtWidgets.QWidget(ACSEL_Starter)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.widgetPics = QtWidgets.QWidget(self.centralwidget)
self.widgetPics.setObjectName("widgetPics")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widgetPics)
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.labelAcsel = QtWidgets.QLabel(self.widgetPics)
self.labelAcsel.setText("")
self.labelAcsel.setObjectName("labelAcsel")
self.horizontalLayout_2.addWidget(self.labelAcsel)
self.labelMubea = QtWidgets.QLabel(self.widgetPics)
self.labelMubea.setText("")
self.labelMubea.setObjectName("labelMubea")
self.horizontalLayout_2.addWidget(self.labelMubea)
self.gridLayout.addWidget(self.widgetPics, 0, 0, 1, 1)
self.widgetProgress = QtWidgets.QWidget(self.centralwidget)
self.widgetProgress.setMaximumSize(QtCore.QSize(16777215, 30))
self.widgetProgress.setObjectName("widgetProgress")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.widgetProgress)
self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetFixedSize)
self.horizontalLayout.setContentsMargins(0, 9, 0, 0)
self.horizontalLayout.setSpacing(6)
self.horizontalLayout.setObjectName("horizontalLayout")
self.labelProgress = QtWidgets.QLabel(self.widgetProgress)
self.labelProgress.setMaximumSize(QtCore.QSize(48, 16777215))
self.labelProgress.setObjectName("labelProgress")
self.horizontalLayout.addWidget(self.labelProgress)
self.lineEditProgress = QtWidgets.QLineEdit(self.widgetProgress)
self.lineEditProgress.setMaximumSize(QtCore.QSize(50, 16777215))
self.lineEditProgress.setObjectName("lineEditProgress")
self.horizontalLayout.addWidget(self.lineEditProgress)
self.labelPercent = QtWidgets.QLabel(self.widgetProgress)
self.labelPercent.setObjectName("labelPercent")
self.horizontalLayout.addWidget(self.labelPercent)
self.gridLayout.addWidget(self.widgetProgress, 1, 0, 1, 1)
ACSEL_Starter.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(ACSEL_Starter)
self.menubar.setGeometry(QtCore.QRect(0, 0, 320, 21))
self.menubar.setObjectName("menubar")
ACSEL_Starter.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(ACSEL_Starter)
self.statusbar.setObjectName("statusbar")
ACSEL_Starter.setStatusBar(self.statusbar)
self.retranslateUi(ACSEL_Starter)
QtCore.QMetaObject.connectSlotsByName(ACSEL_Starter)
def retranslateUi(self, ACSEL_Starter):
_translate = QtCore.QCoreApplication.translate
ACSEL_Starter.setWindowTitle(_translate("ACSEL_Starter", "ACSEL_Starter"))
self.labelProgress.setText(_translate("ACSEL_Starter", "Progress"))
self.labelPercent.setText(_translate("ACSEL_Starter", "%"))
I expect the GUI to be updated whenever I set new text to the lineEdit.
Thank you for your help in advance!

I just found out a solution by my own and used the nicer progress bar instead of the lineEdit.
Here the solution when the progress bar is activated via code and not buttonClick. Because then a new thread has to be performed manually. The buttonClick does it automatically internally.
class ThreadClass(QThread):
valChanged = pyqtSignal(int)
def run(self):
print('run thread') # e.g. file download
count = 0
while count < 100:
count += 0.0005
self.valChanged.emit(count)
print('finished thread')
main_window.my_property = True
self.quit()
class AcselStarter_Thread(QtWidgets.QMainWindow, Ui_ACSEL_Starter):
"""
Activating the progress bar within the code without ButtonClick is not working.
"""
def __init__(self, parent=None):
super(AcselStarter_Thread, self).__init__(parent)
Ui_ACSEL_Starter.__init__(self)
self.setupUi(self)
pixmapAcsel = QPixmap('../fig/ACSEL.png')
self.labelAcsel.setPixmap(pixmapAcsel)
pixmapMubea = QPixmap('../fig/CAELogo_height60.png')
self.labelMubea.setPixmap(pixmapMubea)
self.progressBar.setMaximum(100)
self.progressBar.setValue(0)
self.__my_property = False
#property
def my_property(self):
return self.__my_property
#my_property.setter
def my_property(self, val):
self.__my_property = val
print('new val')
if self.__my_property:
self.do_something_after_progressbar()
def update_progressbar(self, val):
self.progressBar.setValue(val)
def do_thread(self):
# e.g. file update/download
print('do_thread')
self.threadClass = ThreadClass()
self.threadClass.valChanged.connect(self.update_progressbar)
self.threadClass.start()
def do_something_after_progressbar(self):
# e.g. moving the downloaded files and starting the updated app
print('do_something_after_progressbar')
if __name__ == '__main__':
"""
Main method. Starts the application
__name__ == '__main__' is true, if this file is run directly and not imported.
"""
app = QtWidgets.QApplication(sys.argv)
main_window = AcselStarter_Thread()
main_window.show()
main_window.do_thread()
sys.exit(app.exec_())
The output is the following, as expected/wanted:
do_thread
run thread
finished thread
new val
do_something_after_progressbar

Related

How can I run the Python program in the background while GUI is closed? But the GUI can be restored [duplicate]

This question already has answers here:
PyQt - how to detect and close UI if it's already running?
(3 answers)
Closed 6 months ago.
Is there anyway I can run this program like this.
At the start of the program GUI shows and background process starts running. And the the GUI can be closed and opened anytime the user wants. But the background process keeps running uninterrupted.
Here is my current code. 4 classes.
FileHandler
Scanner <- Inherits from QThread
UserInterface <- Takes QMainWindow as an argument
Main <- Inherits from UserInterface
import math
import sys
import time
import psutil
import win32gui
import win32process
import threading
import atexit
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtChart import QChart, QChartView, QPieSeries
from PyQt5.QtCore import QThread, pyqtSignal
RECORDED_PROGRAMS = {}
class FileHandler():
def __init__ (self):
print("[+] Driver File Initiated...")
self.logFile = open("log.txt", "a+")
self.dataFile = open("data.txt", "a+")
def readFile(self):
pass
def writeFile(self):
print("[+] {} : Writing Data to the File...".format(time.strftime("%H:%M:%S".format(time.localtime()))))
self.dataFile.write("\nOn Write : {} : ".format(time.strftime("%H:%M:%S".format(time.localtime()))) + str(RECORDED_PROGRAMS))
def closeFile(self):
print("[+] File Handler Exiting...")
print("[+] Closing File...")
self.dataFile.write("\nOn Exit : {} : ".format(time.strftime("%H:%M:%S".format(time.localtime()))) + str(RECORDED_PROGRAMS))
self.dataFile.write("\n=================================================================================")
self.dataFile.write("\n[!] Program Exited. TimeStamp: {}".format(time.strftime("%H:%M:%S", time.localtime())))
self.dataFile.write("\n=================================================================================")
self.dataFile.close()
self.logFile.close()
#==============================================================================================================
class Scanner(QThread):
signal = pyqtSignal(bool)
def run(self):
print("[+] Scanner Initialized...")
count = 0
while True:
count += 1
try:
activeWindowId = win32gui.GetForegroundWindow()
threadList = win32process.GetWindowThreadProcessId(activeWindowId)
mainThreadName = psutil.Process(threadList[-1]).name()
if(mainThreadName in RECORDED_PROGRAMS.keys()):
RECORDED_PROGRAMS[mainThreadName] += 1
else:
RECORDED_PROGRAMS[mainThreadName] = 1
except Exception as E:
print("[-] Error in Scanner...")
print("======================================================")
print(E)
print("======================================================")
if count == 60:
self.signal.emit(True)
count = 0
time.sleep(1)
#==============================================================================================================
class UserInterface():
def __init__(self, MainWindow):
self.setupUi(MainWindow)
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(640, 480)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
MainWindow.setSizePolicy(sizePolicy)
MainWindow.setMinimumSize(QtCore.QSize(640, 480))
MainWindow.setMaximumSize(QtCore.QSize(640, 480))
font = QtGui.QFont()
font.setFamily("Bahnschrift")
font.setPointSize(14)
MainWindow.setFont(font)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.centralWidgetHLayout = QtWidgets.QHBoxLayout(self.centralwidget)
self.centralWidgetHLayout.setObjectName("centralWidgetHLayout")
self.leftGroupBox = QtWidgets.QGroupBox(self.centralwidget)
self.leftGroupBox.setMinimumSize(QtCore.QSize(300, 462))
self.leftGroupBox.setMaximumSize(QtCore.QSize(300, 462))
self.leftGroupBox.setObjectName("leftGroupBox")
self.leftGroupVLayout = QtWidgets.QVBoxLayout(self.leftGroupBox)
self.leftGroupVLayout.setContentsMargins(5, 5, 5, 5)
self.leftGroupVLayout.setSpacing(5)
self.leftGroupVLayout.setObjectName("leftGroupVLayout")
self.widget = QtWidgets.QWidget(self.leftGroupBox)
self.widget.setMinimumSize(QtCore.QSize(288, 427))
self.widget.setMaximumSize(QtCore.QSize(288, 427))
self.widget.setObjectName("widget")
self.widgetLayout = QtWidgets.QVBoxLayout(self.widget)
self.widgetLayout.setContentsMargins(0, 0, 0, 0)
self.widgetLayout.setSpacing(0)
self.widgetLayout.setObjectName("widgetLayout")
self.series = QPieSeries()
self.chart = QChart()
self.chart.addSeries(self.series)
self.chartView = QChartView(self.chart)
self.chart.setAnimationOptions(QChart.SeriesAnimations)
self.chart.legend().hide()
self.widgetLayout.addWidget(self.chartView)
self.leftGroupVLayout.addWidget(self.widget)
self.centralWidgetHLayout.addWidget(self.leftGroupBox)
self.rightGroupBox = QtWidgets.QGroupBox(self.centralwidget)
self.rightGroupBox.setMinimumSize(QtCore.QSize(316, 462))
self.rightGroupBox.setMaximumSize(QtCore.QSize(316, 462))
self.rightGroupBox.setObjectName("rightGroupBox")
self.rightGroupVLayout = QtWidgets.QVBoxLayout(self.rightGroupBox)
self.rightGroupVLayout.setContentsMargins(5, 5, 5, 5)
self.rightGroupVLayout.setSpacing(5)
self.rightGroupVLayout.setObjectName("rightGroupVLayout")
self.tableView = QtWidgets.QTableWidget(self.rightGroupBox)
self.tableView.setMinimumSize(QtCore.QSize(304, 427))
self.tableView.setMaximumSize(QtCore.QSize(304, 427))
self.tableView.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.tableView.setFrameShadow(QtWidgets.QFrame.Plain)
self.tableView.setLineWidth(1)
self.tableView.setMidLineWidth(0)
self.tableView.setObjectName("tableView")
self.tableView.setColumnCount(2)
self.tableView.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableView.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableView.setHorizontalHeaderItem(1, item)
self.tableView.horizontalHeader().setVisible(True)
self.tableView.horizontalHeader().setDefaultSectionSize(150)
self.tableView.horizontalHeader().setHighlightSections(False)
self.tableView.horizontalHeader().setMinimumSectionSize(150)
self.tableView.verticalHeader().setVisible(True)
self.tableView.verticalHeader().setDefaultSectionSize(31)
self.rightGroupVLayout.addWidget(self.tableView)
self.centralWidgetHLayout.addWidget(self.rightGroupBox)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.leftGroupBox.setTitle(_translate("MainWindow", "Top 10 Overview"))
self.rightGroupBox.setTitle(_translate("MainWindow", "Recorded Programs"))
self.tableView.setSortingEnabled(True)
item = self.tableView.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "Program Name"))
item = self.tableView.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "Time (mins)"))
MainWindow.show()
#===========================================================================================================================
class Main(UserInterface):
def __init__(self, MainWindow):
self.scanner = Scanner()
self.fileHandler = FileHandler()
self.runScanner()
super().__init__(MainWindow)
def runScanner(self):
self.scanner.signal.connect(self.update)
self.scanner.start()
def update(self):
self.updateChart()
self.updateTable()
self.updateLog()
def updateChart(self):
print("[+] Updating Chart...")
self.chart.removeSeries(self.series)
self.series.clear()
for key, val in RECORDED_PROGRAMS.items():
self.series.append(key, math.ceil(val/60))
self.chart.addSeries(self.series)
def updateTable(self):
print("[+] Updating Table...")
rowCount = len(RECORDED_PROGRAMS)
self.tableView.setRowCount(rowCount)
programNames = list(RECORDED_PROGRAMS.keys())
timeRec = list(RECORDED_PROGRAMS.values())
for row in range(rowCount):
for column in range(2):
if column == 0:
self.tableView.setItem(row, column, QtWidgets.QTableWidgetItem(str(programNames[row])))
if column == 1:
self.tableView.setItem(row, column, QtWidgets.QTableWidgetItem(str(math.ceil(timeRec[row]/60))))
def updateLog(self):
print("[+] Updating Log...")
self.fileHandler.writeFile()
def quit(self):
print("[+] Quitting Program...")
self.scanner.terminate()
self.fileHandler.closeFile()
#===========================================================================================================================
def _exit():
print("[+] At Exit Func Triggered...")
main.quit()
if __name__ == "__main__":
guiApplication = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
main = Main(window)
atexit.register(_exit)
stop = False
while not stop:
answer = input("Stop [Y/N]? ")
if answer == "Y":
stop = True
time.sleep(0.5)
print("[+] Main Loop Exit hit...")
There are a couple ways you can do this. You can set it to hide windows with self.hide() and self.show() to show them again, or you can use the self.setVisible(False) on each window you want to hide. You can loop through them to hide all of them. You could either leave one window open with a push button to call the functions to show and hide them, or you can use another library like pynput to set keybinds to show or hide the window. Of course you should make a seperate function for this and call it by the push button or keybind, and you can choose what to do in the function by checking if self.isVisible(). The name doesn't have to be self, it can be each one you want to hide and you can loop through them and use a comprehension or lambda function.

How to create a Drawer instance and attach it to MainWindow

I am struggling to add a side menu to my application.
I have a QMainWindow instance to which I was hoping to add a QDrawer object and achieve an effect similar to this sample.
Unfortunately, it seems that PySide2 only provides QMenu, QTooltip and QDialog widgets which inherit from the Popup class, and QDrawer is nowhere to be found. However, using a Drawer tag in a QML file works just fine. Shouldn't it be possible to also create an instance of QDrawer programmatically?
As another try, I tried to load a Drawer instance from a QML file and attach it to my QMainWindow. Unfortunately I can't quite understand what should I specify as parent, what should I wrap it in, what parameters should I use etc. - any advice would be appreciated (although I would much rather create and configure it programatically).
My goal is to create a QMainWindow with a toolbar, central widget and a QDrawer instance as a side navigation menu (such as in this sample). Can you please share some examples or explain what to do?
One possible solution is to implement a Drawer using Qt Widgets, the main feature is to animate the change of width for example using a QXAnimation, the other task is to set the anchors so that it occupies the necessary height. A simple example is the one shown in the following code:
import os
from PySide2 import QtCore, QtGui, QtWidgets
class Drawer(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedWidth(0)
self.setContentsMargins(0, 0, 0, 0)
# self.setFixedWidth(0)
self._maximum_width = 0
self._animation = QtCore.QPropertyAnimation(self, b"width")
self._animation.setStartValue(0)
self._animation.setDuration(1000)
self._animation.valueChanged.connect(self.setFixedWidth)
self.hide()
#property
def maximum_width(self):
return self._maximum_width
#maximum_width.setter
def maximum_width(self, w):
self._maximum_width = w
self._animation.setEndValue(self.maximum_width)
def open(self):
self._animation.setDirection(QtCore.QAbstractAnimation.Forward)
self._animation.start()
self.show()
def close(self):
self._animation.setDirection(QtCore.QAbstractAnimation.Backward)
self._animation.start()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowFlag(QtCore.Qt.FramelessWindowHint)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
self.tool_button = QtWidgets.QToolButton(
checkable=True, iconSize=QtCore.QSize(36, 36)
)
content_widget = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
content_widget.setText("Content")
content_widget.setStyleSheet("background-color: green")
lay = QtWidgets.QVBoxLayout(central_widget)
lay.setSpacing(0)
lay.setContentsMargins(0, 0, 0, 0)
lay.addWidget(self.tool_button)
lay.addWidget(content_widget)
self.resize(640, 480)
self.drawer = Drawer(self)
self.drawer.move(0, self.tool_button.sizeHint().height())
self.drawer.maximum_width = 200
self.drawer.raise_()
content_lay = QtWidgets.QVBoxLayout()
content_lay.setContentsMargins(0, 0, 0, 0)
label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
label.setText("Content\nDrawer")
label.setStyleSheet("background-color: red")
content_lay.addWidget(label)
self.drawer.setLayout(content_lay)
self.tool_button.toggled.connect(self.onToggled)
self.onToggled(self.tool_button.isChecked())
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.onCustomContextMenuRequested)
#QtCore.Slot()
def onCustomContextMenuRequested(self):
menu = QtWidgets.QMenu()
quit_action = menu.addAction(self.tr("Close"))
action = menu.exec_(QtGui.QCursor.pos())
if action == quit_action:
self.close()
#QtCore.Slot(bool)
def onToggled(self, checked):
if checked:
self.tool_button.setIcon(
self.style().standardIcon(QtWidgets.QStyle.SP_MediaStop)
)
self.drawer.open()
else:
self.tool_button.setIcon(
self.style().standardIcon(QtWidgets.QStyle.SP_MediaPlay)
)
self.drawer.close()
def resizeEvent(self, event):
self.drawer.setFixedHeight(self.height() - self.drawer.pos().y())
super().resizeEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

PyQt5 - how to enable a new (third) button that fail to show after running clicked pushButton?

Here is a simple program to create 2 pushbuttons and a third pushbutton when either of the first two buttons is clicked. But it doesn't work. When I click one of the first two buttons I get the message in the console indicating it has been clicked but no 3rd button appears. Why?? Thanks!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
def setup_pushButton(self, word, x, y, width, height):
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setGeometry(QtCore.QRect(x, y, width, height))
self.pushButton.setText(word)
self.pushButton.clicked.connect(self.but_clicked)
def create_pushButtons(self):
self.setup_pushButton('apple', 100, 110, 75, 23)
self.setup_pushButton('car', 20, 110, 75, 23)
def but_clicked(self):
print('clicked')
self.setup_pushButton('house', 250, 110, 75, 23)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
ui.create_pushButtons()
Form.show()
sys.exit(app.exec_())
Below code with inline commenting will help you figure out what went wrong and why I put things where they are. Most important... your button names may change every now and then therefor I've made the code variable for you by using setattr and getattr. Less work to do afterwards and more pythonic with an eye on OOP ;-)
Note: Normally initialization of buttons occur in the setupUI by convention. In your case we treat the buttons as additions to the main setupUI not taken into account earlier because its an additional feature in a fictional product asked by your beloved product launching customer.
Enjoy!
Tributton example:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(QtWidgets.QWidget, object):
def __init__(self, parent=None):
print '> This is start of main app'
super(Ui_Form, self).__init__(parent)
self.setupUI(self)
self.buttonlist = [('apple', 100, 110, 75, 23),
('car', 20, 110, 75, 23),
('house', 250, 110, 75, 23)]
self.create_pushButtons()
print '> Everything is painted... lets show it on screen.'
def setupUI(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Twobutton Example", "Twobutton Example"))
def create_pushButtons(self):
for item in self.buttonlist:
# set attribute with variable name (e.g. "car" may change into "cars")
setattr(self, 'pushButton_%s' % (item[0]), QtWidgets.QPushButton(self))
# painting the variale named button.
# x, y, width, height
getattr(self, 'pushButton_%s' % (item[0])).setGeometry(QtCore.QRect(item[1], item[2], item[3], item[4]))
getattr(self, 'pushButton_%s' % (item[0])).setText(item[0])
# create the connection aswell for the variable named button in a single "go".
if item[0] in [self.buttonlist[0][0], self.buttonlist[1][0]]:
getattr(self, 'pushButton_%s' % (item[0])).clicked.connect(self.buton_clicked)
if item[0] == self.buttonlist[2][0]:
getattr(self, 'pushButton_%s' % (item[0])).clicked.connect(self.house_but_clicked)
getattr(self, 'pushButton_%s' % (item[0])).hide()
def buton_clicked(self):
#"Murder she wrote".. : who done it... was it car or apple... where did the order came from?
sender = self.sender()
text = sender.text()
print('The button %s was clicked' % text)
# print 'clicked' to python standard out. In an editor like komodo edit you see imidiatly what you do.
sys.stdout.flush()
# car button:
# if button house is hidden... lets show it (again).
if text in [self.buttonlist[1][0], ]:
getattr(self, 'pushButton_%s' % (self.buttonlist[2][0])).show()
# apple button:
# if button house is show... lets hide it again.
if text in [self.buttonlist[0][0], ]:
getattr(self, 'pushButton_%s' % (self.buttonlist[2][0])).hide()
def house_but_clicked(self):
sender = self.sender()
print('The button %s was clicked and its going to be connected to something else' % sender.text())
sys.stdout.flush()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ui = Ui_Form()
ui.show()
sys.stdout.flush()
sys.exit(app.exec_())
EDIT : to show inccorect use of variable objectname after comment OP on december 10th.
OP script:
snippet...
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
t = ui
ui.create_pushButtons()
Form.show()
# print dir(__builtins__)
# l = dir(Ui_Form.setup_pushButton)
# from pprint import pprint
# pprint(l)
# t = Ui_Form()
variables = [i for i in dir(t) if not inspect.ismethod(i)]
print variables
sys.exit(app.exec_())
Output print variables:
['class', 'delattr', 'dict', 'doc', 'format', 'getattribute', 'hash', 'init', 'module', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', 'weakref', 'but_clicked', 'create_pushButtons', 'pushButton1', 'setupUi', 'setup_pushButton']
Tributton example script:
snippet...
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ui = Ui_Form()
t = ui
ui.show()
sys.stdout.flush()
variables = [i for i in dir(t) if not inspect.ismethod(i)]
print variables
sys.exit(app.exec_())
Output print variables:
This is start of main app
Everything is painted... lets show it on screen.
['DrawChildren', 'DrawWindowBackground', 'IgnoreMask', 'PaintDeviceMetric',
...
'pos', 'previousInFocusChain', 'property', 'pushButton_apple', 'pushButton_car', 'pushButton_house', 'pyqtConfigure', 'raise_', 'receivers', 'rect', 'releaseKeyboard',
...
'windowOpacity', 'windowRole', 'windowState', 'windowTitle', 'windowTitleChanged', 'windowType', 'x', 'y']
As you can see there are three separate atributes with their own objectName space, namely ...'pushButton_apple', 'pushButton_car' and 'pushButton_house'.
Actually, my code did produce the new button it just wasn't showing. By adding --self.pushButton.show() -- it now works fine. Here's the complete revised code that works.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
def setup_pushButton(self, word, x, y, width, height):
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setGeometry(QtCore.QRect(x, y, width, height))
self.pushButton.setText(word)
self.pushButton.clicked.connect(self.but_clicked)
def create_pushButtons(self):
self.setup_pushButton('apple', 100, 110, 75, 23)
self.setup_pushButton('car', 20, 110, 75, 23)
def but_clicked(self):
print('clicked')
self.setup_pushButton('house', 250, 110, 75, 23)
self.pushButton.show()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
ui.create_pushButtons()
Form.show()
sys.exit(app.exec_())

PyQt VTK on OSX only show up in the lower left of the display window

I encountered a strange problem while using Python 2.7, PyQT5.6 and VTK7.1 on OSX. The render window only take the lower left quarter of the entire display window. While I tried the same code on windows with same versions of libs, it worked fine. The code is as following:
from PyQt5.QtWidgets import *
import vtk
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
import sys
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(603, 553)
self.centralWidget = QWidget(MainWindow)
self.gridlayout = QGridLayout(self.centralWidget)
self.vtkWidget = QVTKRenderWindowInteractor(self.centralWidget)
self.gridlayout.addWidget(self.vtkWidget, 0, 0, 100, 100)
self.buttonLeft = QPushButton("Left")
self.gridlayout.addWidget(self.buttonLeft, 96,48,1,1)
self.buttonRight = QPushButton("Right")
self.gridlayout.addWidget(self.buttonRight, 96,52,1,1)
self.buttonUp= QPushButton("Up")
self.gridlayout.addWidget(self.buttonUp, 94,50,1,1)
self.buttonDown = QPushButton("Down")
self.gridlayout.addWidget(self.buttonDown, 98,50,1,1)
self.buttonFire = QPushButton("Fire Torpedo")
self.gridlayout.addWidget(self.buttonFire, 95,50,3,1)
MainWindow.setCentralWidget(self.centralWidget)
class SimpleView(QMainWindow):
def __init__(self, parent = None):
QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ren = vtk.vtkRenderer()
self.ui.vtkWidget.GetRenderWindow().AddRenderer(self.ren)
self.iren = self.ui.vtkWidget.GetRenderWindow().GetInteractor()
# Create source
source = vtk.vtkSphereSource()
source.SetCenter(0, 0, 0)
source.SetRadius(5.0)
# Create a mapper
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(source.GetOutputPort())
# Create an actor
actor = vtk.vtkActor()
actor.SetMapper(mapper)
self.ren.AddActor(actor)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = SimpleView()
window.show()
window.iren.Initialize() # Need this line to actually show the render inside Qt
sys.exit(app.exec_())
The result looks like this on OSX:
display result in OSX
Please notice that the buttons didn't even show up.
And the result looks like this on Windows:
display result in Windows
Please let me know if you have any suggestions.
Many thanks.

Pyside crashes when executing function twice

Why does my application crash when i run the function setup_controls() twice.
Am I missing a 'parent/self' somewhere that is critical in the design?
import sys
from PySide import QtGui, QtCore
class QCategoryButton(QtGui.QPushButton):
def __init__(self, Text, treeitem, parent=None):
super(QCategoryButton, self).__init__(Text, parent)
self.treeitem = treeitem
def mousePressEvent(self, event):
mouse_button = event.button()
if mouse_button == QtCore.Qt.LeftButton:
self.treeitem.setExpanded(not self.treeitem.isExpanded())
class Example(QtGui.QWidget):
def __init__(self,):
super(Example, self).__init__()
self.initUI()
def initUI(self):
# formatting
self.resize(300, 300)
self.setWindowTitle("Example")
# widgets
self.ui_treeWidget = QtGui.QTreeWidget()
self.ui_treeWidget.setRootIsDecorated(False)
self.ui_treeWidget.setHeaderHidden(True)
self.ui_treeWidget.setIndentation(0)
self.setup_controls()
# self.setup_controls()
# layout
self.mainLayout = QtGui.QGridLayout(self)
self.mainLayout.addWidget(self.ui_treeWidget)
self.show()
def setup_controls(self):
# Add Category
pCategory = QtGui.QTreeWidgetItem()
self.ui_treeWidget.addTopLevelItem(pCategory)
self.ui_toggler = QCategoryButton('Settings', pCategory)
self.ui_treeWidget.setItemWidget(pCategory, 0, self.ui_toggler)
pFrame = QtGui.QFrame(self.ui_treeWidget)
pLayout = QtGui.QVBoxLayout(pFrame)
self.ui_ctrl = QtGui.QPushButton('Great')
self.ui_ctrlb = QtGui.QPushButton('Cool')
pLayout.addWidget(self.ui_ctrl)
pLayout.addWidget(self.ui_ctrlb)
pContainer = QtGui.QTreeWidgetItem()
pContainer.setDisabled(False)
pCategory.addChild(pContainer)
self.ui_treeWidget.setItemWidget(pContainer, 0, pFrame)
# Main
# ------------------------------------------------------------------------------
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
The setItemWidget method takes ownership of the widget that is passed to it. If you don't keep a reference it, it could get garbage-collected by Python. But of course Qt knows nothing about Python, so when it subsequently tries to access the widget that is no longer there ... boom!
This is the problematic line:
self.ui_toggler = QCategoryButton('Settings', pCategory)
On the second call, the previous widget stored in self.ui_toggler will get deleted, because there is no other reference held for it (on the Python side). So instead you should do this:
ui_toggler = QCategoryButton('Settings', pCategory, self)
self.ui_treeWidget.setItemWidget(pCategory, 0, ui_toggler)

Categories