access instance variable by name from function - python-3.x

I need to make a UI for a class which makes a number of calculations from a set of variables. The code roughly looks like this:
class MainWindow:
def __init__(self):
pulse = Pulse()
self.var1_lineEdit.textEdited.connect(self.set_attribute(pulse, "var1", new_value))
self.var2_lineEdit.textEdited.connect(self.set_attribute(pulse, "var2", new_value))
self.var3_lineEdit.textEdited.connect(self.set_attribute(pulse, "var3", new_value))
....
def set_attribute(pulse, var_name, value):
# get value from line edit
# update value in pulse
# update other calculations
class Pulse:
def __init__(self):
var1 = 1
var2 = 2
var3 = 3
....
My problem here is how to code set_attribute. Is there a way to access individual variables of another class by passing the name as a function argument? I would like to avoid having to define a new function for each variable.
Or is there a simpler way to do this? I am not very familiar with OOP and the proper way of coding UIs.

EDIT
The signal/slot connections you've proposed will get you in trouble. Signals are connected to slots using the connect function, which accepts a python callable as its argument--not the function call itself. That's the difference between
widget.textChanged.connect(self.set_attribute) # right syntax
widget.textChanged.connect(self.set_attribute()) # wrong syntax
So then, how do you tell set_attribute what to do? ekhumoro informed me the error of my ways re: use of QSignalMapper. It's an outdated technique. Best to simply use lambda functions (or partials) to get the desired effect.
I updated my demo for use of lambdas
For the purposes of this demo, I've created a simple QMainWindow with two QLineEdit widgets and a QPushButton.
# file ui_main.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(359, 249)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.formLayoutWidget = QtWidgets.QWidget(self.centralwidget)
self.formLayoutWidget.setGeometry(QtCore.QRect(0, 0, 351, 51))
self.formLayoutWidget.setObjectName("formLayoutWidget")
self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
self.formLayout.setObjectName("formLayout")
self.configParam1Label = QtWidgets.QLabel(self.formLayoutWidget)
self.configParam1Label.setObjectName("configParam1Label")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.configParam1Label)
self.configEntry = QtWidgets.QLineEdit(self.formLayoutWidget)
self.configEntry.setObjectName("configEntry")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.configEntry)
self.configParam2Label = QtWidgets.QLabel(self.formLayoutWidget)
self.configParam2Label.setObjectName("configParam2Label")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.configParam2Label)
self.configEntry2 = QtWidgets.QLineEdit(self.formLayoutWidget)
self.configEntry2.setObjectName("configEntry2")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.configEntry2)
self.pulseButton = QtWidgets.QPushButton(self.centralwidget)
self.pulseButton.setGeometry(QtCore.QRect(130, 140, 75, 23))
self.pulseButton.setObjectName("pulseButton")
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.configParam1Label.setText(_translate("MainWindow", "Config Param 1"))
self.configParam2Label.setText(_translate("MainWindow", "Config Param 2"))
self.pulseButton.setText(_translate("MainWindow", "GetPulse"))
In another file, after some imports, define Pulse--a simple class that contains two attributes
# file main.py
from PyQt5.QtCore import (QSignalMapper, pyqtSlot)
from PyQt5.QtWidgets import (QApplication, QMainWindow, QMessageBox)
from ui_main import Ui_MainWindow
class Pulse:
def __init__(self):
self.param_one = None
self.param_two = None
Now, define MainWindow, setting up its UI and giving it a Pulse:
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.pulse = Pulse()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.widget_one = self.ui.configEntry
self.widget_two = self.ui.configEntry2
self.pulse_button = self.ui.pulseButton
self.widget_one.textChanged.connect(lambda: self.widget_handler('param_one', self.widget_one.text()))
self.widget_one.textChanged.connect(lambda: self.widget_handler('param_two', self.widget_two.text()))
def widget_handler(self, attr, value):
setattr(self.pulse,attr,value)
def handler(self, idx):
widget, attr = self.attribute_widget_list[idx]
widget_value = widget.text()
setattr(self.pulse,attr,widget_value)
setattr is equivalent to, for example, self.pulse.param_one = widget_value.
To prove it works, let's use that QPushButton to probe the state of Pulse:
#pyqtSlot()
def on_pulseButton_clicked(self):
message = QMessageBox()
message.setText("{} - {}".format(self.pulse.param_one, self.pulse.param_two))
message.exec()
Here I'm using a different signal/slot connection scheme, which you can read about here
And here's how we run the script:
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Hope that helps!

Related

PyQt5: Qstyle.CC_ScrollBar rendered in the wrong place

I am working with a listView and a custom delegate. Through the paint function I draw a set of control elements so that each row of the list acts as if it was a widget, without actually being one. This is crucial for performance since the list is composed of hundreds of thousands of elements, as pointed here and here.
The only problem is with QStyleOptionSlider complex control: if I ask for a CC.ScrollBar the control is rendered in the top left corner of the view and not where i want. If in QApplication.style().drawComplexControl(QStyle.CC_ScrollBar, self.scrollOptions, painter) i ask for a CC_Slider (instead of CC_ScrollBar) the control is rendered where expected.
I also tried to initialise the style from a real scroll widget but nothing changed.
I would like to know if I'm doing something wrong or if it's a problem with the library, since all the other controls i have painted work perfectly. The only difference I've noticed is that other elements (e.g. frame, label, pushbutton) have their own QStyleOption class while the scrollbar is merged with the slider class, but to quote the docs:
QStyleOptionSlider contains all the information that QStyle functions need to draw QSlider and QScrollBar.
Debug Info: Python 3.8.6 / PyQt 5.15.1 / Pyqt-tools 5.15.1.2 / Windows 10
Minimal example
from PyQt5.QtCore import QSize, Qt, QRect
from PyQt5.QtGui import QColor
from PyQt5.QtGui import QStandardItem
from PyQt5.QtGui import QStandardItemModel
from PyQt5.QtWidgets import QStyle
from PyQt5.QtWidgets import QStyledItemDelegate, QApplication, QStyleOptionFrame, \
QStyleOptionSlider
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
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.inferenceListView = QtWidgets.QListView(self.centralwidget)
self.inferenceListView.setGridSize(QtCore.QSize(0, 200))
self.inferenceListView.setObjectName("inferenceListView")
self.gridLayout.addWidget(self.inferenceListView, 0, 1, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
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)
self.setupProposals()
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
def setupProposals(self):
self.delegate = MyDelegate()
# self.delegate.initScroll(self.horizontalScrollBar)
model = QStandardItemModel(0, 0)
for index in range(0, 5000):
model.appendRow(QStandardItem(str(index)))
self.inferenceListView.setItemDelegateForRow(index, self.delegate)
self.inferenceListView.setModel(model)
class MyDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
QStyledItemDelegate.__init__(self, parent)
self.frame = QStyleOptionFrame()
# ---------------
self.scrollOptions = QStyleOptionSlider()
self.scrollOptions.orientation = Qt.Vertical
self.scrollOptions.LayoutDirectionAuto = Qt.LayoutDirectionAuto
self.scrollOptions.orientation = Qt.Vertical
self.scrollOptions.state = QStyle.State_Enabled
self.scrollOptions.maximum = 10
self.scrollOptions.minimum = 0
self.scrollOptions.sliderValue = 0
def initScroll(self, scroll):
self.scrollOptions.initFrom(scroll)
def sizeHint(self, option, index):
return QSize(150, 200)
def paint(self, painter, option, index):
optX = option.rect.x()
optY = option.rect.y()
optH = option.rect.height()
optW = option.rect.width()
painter.fillRect(option.rect, QColor(100, 100, 100, 100))
painter.drawLine(optX, optY + optH, optX + optW, optY + optH)
QApplication.style().drawControl(QStyle.CE_ShapedFrame, self.frame, painter)
self.scrollOptions.rect = QRect(optX + 100, optY + 100, 50, 80)
# OK WITH CC_SLIDER
#QApplication.style().drawComplexControl(QStyle.CC_Slider, self.scrollOptions, painter)
# WRONG PLACE WITH CC_SCROLLBAR
QApplication.style().drawComplexControl(QStyle.CC_ScrollBar, self.scrollOptions, painter)
def editorEvent(self, event, model, option, index):
return False
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_())
EDIT
Seems to be a Windows-related problem at the moment. I had a colleague with a Mac run the code above and the scrollbar is drawn in the correct place. I attach an image of what happens on Windows in the two cases:
It seems like a possibly incomplete implementation of subControlRect in QCommonStyle, as the rectangle returned for CC_Slider is always positioned on the top left (see source).
A possible solution can be to use a proxy style and return a translated rectangle if the subrect is not contained in the option rect:
class ProxyStyle(QtWidgets.QProxyStyle):
def subControlRect(self, cc, opt, sc, widget=None):
r = super().subControlRect(cc, opt, sc, widget)
if cc == self.CC_ScrollBar and not opt.rect.contains(r):
r.translate(opt.rect.topLeft())
return r
# ...
app = QtWidgets.QApplication(sys.argv)
app.setStyle(ProxyStyle())

Python PyQt5 Terminal Command execution problem on a button click

I'm trying to create an application, that can execute an embedded Terminal command when ever the button is clicked. The actual problem occurs when i click the button and nothing happens.
I have two scripts one has a terminal widget and the other has the main GUI. Any Help, would be highly appreciated.
That's first Script
import sys
from PyQt5 import QtCore, QtWidgets
class EmbTerminal(QtWidgets.QWidget):
def __init__(self, parent=None):
super(EmbTerminal, self).__init__(parent)
self._process = []
self.start_process('urxvt',['-embed', str(int(self.winId())),"-e","tmux"])
def start_process(self,prog,options):
child = QtCore.QProcess(self)
self._process.append(child)
child.start(prog,options)
def run_command(self, command = "ls" ):
program = "tmux"
options = []
options.extend(["send-keys"])
options.extend([command])
options.extend(["Enter"])
self.start_process(program, options)
That's Second Script
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(745, 496)
self.tabWidget = QtWidgets.QTabWidget(Dialog)
self.tabWidget.setGeometry(QtCore.QRect(100, 190, 561, 261))
self.tabWidget.setObjectName("tabWidget")
self.tab = QtWidgets.QWidget()
self.tab.setObjectName("tab")
self.tabWidget.addTab(EmbTerminal(), "Terminal")
self.tab_2 = QtWidgets.QWidget()
self.tab_2.setObjectName("tab_2")
self.tabWidget.addTab(self.tab_2, "")
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(280, 70, 211, 71))
self.pushButton.setObjectName("pushButton")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
self.pushButton.clicked.connect(lambda: EmbTerminal.run_command(EmbTerminal(), "ls"))
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("Dialog", "Tab 1"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("Dialog", "Tab 2"))
self.pushButton.setText(_translate("Dialog", "ls"))
from terminal5 import EmbTerminal
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
You should consider the following:
You should not modify the code generated by Qt Designer (unless you understand its logic)
Do not implement the logic in the class generated by Qt Designer, it is advisable to create a new class that inherits from the appropriate widget and use the other class to fill it.
In your case the problem is that the EmbTerminal() object in lambda: EmbTerminal.run_command(EmbTerminal(), "ls") only exists while the lambda is running, but the lambda runs for a very short time causing the command not to be sent causing the error.
Considering the above, the solution is:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(745, 496)
self.tabWidget = QtWidgets.QTabWidget(Dialog)
self.tabWidget.setGeometry(QtCore.QRect(100, 190, 561, 261))
self.tabWidget.setObjectName("tabWidget")
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(280, 70, 211, 71))
self.pushButton.setObjectName("pushButton")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton.setText(_translate("Dialog", "ls"))
from terminal5 import EmbTerminal
class Dialog(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.terminal = EmbTerminal()
self.tabWidget.addTab(self.terminal, "Terminal")
self.pushButton.clicked.connect(self.on_clicked)
#QtCore.pyqtSlot()
def on_clicked(self):
self.terminal.run_command("ls")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Dialog()
w.show()
sys.exit(app.exec_())
On the other hand if you are only going to send commands then it is not necessary to store the QProcess, instead use QProcess: startDetached and make run_command a classmethod:
class EmbTerminal(QtWidgets.QWidget):
# ...
#staticmethod
def run_command(command = "ls" ):
program = "tmux"
options = []
options.extend(["send-keys"])
options.extend([command])
options.extend(["Enter"])
QtCore.QProcess.startDetached(program, options)

How to remove all widgets within a QGroupBox in PyQt5?

In my program there is a QGroupBox displayed that has many QPushButton's within it. During the execution of the program, the user can click a button outside of the QGroupBox and all of the buttons within it will be removed or hidden. Problem is that I can't seem to find a way to do this to the buttons directly or by clearing the QGroupBox.
I have already tried deleteLater on the buttons but that didn't work. I then tried clearing the layout of the QGroupBox but that didn't work either. Here is some code I just wrote up that has a the same problem:
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
import random
class UI_Dialog(object):
def addButtons(self,looping):
# Code to remove the previous QPushButton's goes here.
placement = -100
for i in range(looping):
currentName = 'btn' + str(i)
placement = placement + 110
self.btnB = QtWidgets.QPushButton(self.groupBox)
self.btnB.setGeometry(QtCore.QRect(10+placement, 30+placement, 100, 100))
self.btnB.show()
self.btnB.setObjectName(currentName)
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(1300, 800)
self.btnA = QtWidgets.QPushButton(Dialog)
self.btnA.setGeometry(QtCore.QRect(10, 80, 101, 131))
self.btnA.setObjectName("btn1")
self.btnA.clicked.connect(self.pushed)
self.formLayout = QtWidgets.QFormLayout()
self.groupBox = QtWidgets.QGroupBox("Results")
self.groupBox.setLayout(self.formLayout)
self.resultScrollArea = QtWidgets.QScrollArea(Dialog)
self.resultScrollArea.setWidget(self.groupBox)
self.resultScrollArea.setGeometry(QtCore.QRect(20, 220, 1011, 531))
self.resultScrollArea.setWidgetResizable(True)
self.resultScrollArea.setObjectName("resultScrollArea")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def pushed(self):
unkownLength = random.randint(1,20)
self.addButtons(unkownLength)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Example Program"))
self.btnA.setText(_translate("Dialog", "Push Button"))
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = UI_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
There are things here that probably don't make sense like the window size, the multiple function calls or it being a Dialog window instead of a QMainWindow. However, in the context of the actual program they do make sense so just ignore that, I know it's inefficient. Also the whole point of the unkownLength variable is to emulate that in the actual program, the number of buttons generated will be determined by user input. The buttons must also not be there at the start so that is why they're created with a button click. When the button is clicked again it should remove or hide all the buttons it created before. Any ideas?
Taking advantage that the buttons are children of the QGroupBox we can get the buttons using findChildren() to use deleteLater():
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
import random
class UI_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(1300, 800)
self.btnA = QtWidgets.QPushButton(Dialog)
self.btnA.setGeometry(QtCore.QRect(10, 80, 101, 131))
self.btnA.setObjectName("btn1")
self.formLayout = QtWidgets.QFormLayout()
self.groupBox = QtWidgets.QGroupBox("Results")
self.groupBox.setLayout(self.formLayout)
self.resultScrollArea = QtWidgets.QScrollArea(Dialog)
self.resultScrollArea.setWidget(self.groupBox)
self.resultScrollArea.setGeometry(QtCore.QRect(20, 220, 1011, 531))
self.resultScrollArea.setWidgetResizable(True)
self.resultScrollArea.setObjectName("resultScrollArea")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Example Program"))
self.btnA.setText(_translate("Dialog", "Push Button"))
class Dialog(QtWidgets.QDialog, UI_Dialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setupUi(self)
self.btnA.clicked.connect(self.pushed)
#QtCore.pyqtSlot()
def pushed(self):
unkownLength = random.randint(1, 20)
self.addButtons(unkownLength)
def addButtons(self, looping):
for button in self.groupBox.findChildren(QtWidgets.QPushButton):
button.deleteLater()
placement = -100
pos = QtCore.QPoint(20, 40)
for i in range(looping):
currentName = "btn" + str(i)
self.btnB = QtWidgets.QPushButton(
self.groupBox, objectName=currentName
)
self.btnB.setGeometry(QtCore.QRect(pos, QtCore.QSize(100, 100)))
pos += QtCore.QPoint(110, 110)
self.btnB.show()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Dialog()
w.show()
sys.exit(app.exec_())

How to trigger text in a widget using PyQt

This may look like a long question but it is actually really short, I've just decided to copy all the working code here.
I have a main window and a Tip of the Day widget.
I generated both the UI using the PyQt Designer.
I can open the Tip of the Day widget from the main window menu but I'm not able to make the buttons work:
I'd like to replace some text in the Tip of the Day widget when the previous and the next buttons are clicked.
I have the following main window called MainWindow.py:
from PyQt4 import QtCore, QtGui
from MainWindowUi import Ui_MainWindow
from FormUi import Ui_Form
class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
# Main window user interface elements
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# Main window signal/slot connections
self.setupConnections()
#QtCore.pyqtSlot()
def showTipDialog(self):
'''Trig dialog Tip'''
form = QtGui.QDialog()
form.ui = Ui_Form()
form.ui.setupUi(form)
form.exec_()
def setupConnections(self):
'''Signal and Slot Support'''
self.connect(self.ui.actionTip_of_the_Day, QtCore.SIGNAL('triggered()'), self.showTipDialog)
I have the following main.py:
import sys
from PyQt4 import QtGui
from MainWindow import MainWindow
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
I have the following main window UI called MainWindowUi.py:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'MainWindow.ui'
#
# Created: Thu May 21 20:26:31 2015
# by: PyQt4 UI code generator 4.11.3
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(800, 600)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName(_fromUtf8("menubar"))
self.menuHelp = QtGui.QMenu(self.menubar)
self.menuHelp.setObjectName(_fromUtf8("menuHelp"))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
MainWindow.setStatusBar(self.statusbar)
self.actionTip_of_the_Day = QtGui.QAction(MainWindow)
self.actionTip_of_the_Day.setObjectName(_fromUtf8("actionTip_of_the_Day"))
self.menuHelp.addAction(self.actionTip_of_the_Day)
self.menubar.addAction(self.menuHelp.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
self.menuHelp.setTitle(_translate("MainWindow", "Help", None))
self.actionTip_of_the_Day.setText(_translate("MainWindow", "Tip of the Day", None))
I have the following widget form UI FormUi.py:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'Form.ui'
#
# Created: Thu May 21 23:57:41 2015
# by: PyQt4 UI code generator 4.11.3
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(418, 249)
self.verticalLayout = QtGui.QVBoxLayout(Form)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.lineEdit = QtGui.QLineEdit(Form)
self.lineEdit.setObjectName(_fromUtf8("lineEdit"))
self.verticalLayout.addWidget(self.lineEdit)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.pushButton_previous = QtGui.QPushButton(Form)
self.pushButton_previous.setObjectName(_fromUtf8("pushButton_previous"))
self.horizontalLayout.addWidget(self.pushButton_previous)
self.pushButton_next = QtGui.QPushButton(Form)
self.pushButton_next.setObjectName(_fromUtf8("pushButton_next"))
self.horizontalLayout.addWidget(self.pushButton_next)
self.verticalLayout.addLayout(self.horizontalLayout)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
self.lineEdit.setText(_translate("Form", "Here a tip I'd like to replace by pressing the buttons below.", None))
self.pushButton_previous.setText(_translate("Form", "Previous Tip", None))
self.pushButton_next.setText(_translate("Form", "Next Tip", None))
Please run main.py in order to open the main window and click Help > Tip of the Day to open the widget.
Thanks for the attention.
You have a MainWindow class (which you instantiate from the main() function) which you have written to instantiate your Ui_MainWindow class (thus creating the GUI) and link a button to a method which pops up the dialog.
Now just apply the same logic to the dialog. Instead of creating a QDialog() directly in showTipDialog, instead instantiate a subclass QDialog. Write the subclass in a similar way to what you've done for MainWindow. Connect the clicked signals from the prev/next pushbuttons to appropriate methods (which you write) that change the contents of the QLineEdit.

KeypressEvent not working, How to correct it?

I am trying to get keypressevent work with the following code
import sys,
from PyQt4 import QtCore, QtGui
class Ui_MainWindow(QtGui.QWidget):
def __init__(self):
super(Ui_MainWindow, self).__init__()
def keyPressEvent(self, event):
print 'a'
def setupUi(self, MainWindow):
MainWindow.setObjectName(("MainWindow"))
MainWindow.resize(371, 345)
MainWindow.setMaximumSize(QtCore.QSize(401, 600))
MainWindow.setWindowIcon(QtGui.QIcon('icons/icon.png'))
screen = QtGui.QDesktopWidget().screenGeometry()
mysize = MainWindow.geometry()
hpos = ( screen.width() - mysize.width() ) / 2
vpos = ( screen.height() - mysize.height() ) / 2
MainWindow.move(hpos, vpos)
#some GUI
MainWindow.setCentralWidget(self.centralwidget)
cd=MainWindow.centralWidget()
cd.setFocusPolicy(QtCore.Qt.StrongFocus)
cd.setFocus()
self.actionHardware = QtGui.QAction(MainWindow)
self.actionHardware.setObjectName(("actionHardware"))
self.retranslateUi(MainWindow)
#COnnect odes
def retranslateUi(self, MainWindow):
#sime button text codes
if __name__=="__main__" :
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
The code was partially generated using QTDesigner. I noticed that replacing Mainwindow.show() by ui.show() enables keypressevent but at the cost of not showing any buttons i create in the Mainwindow central widget
It looks like the problem is in the way you are re-using the code output by Designer. You defined Ui_MainWindow.keyPressEvent, and created an instance "ui" of the class. However: "ui" is never directly incorporated into the GUI anywhere (ui.setupUi adds other widgets, but not itself, to MainWindow) and thus events are never delivered to ui.
My approach would look more like this:
class Ui_MainWindow(object): ## note this does not need to inherit QWidget
... ## and ideally, this code should not be changed
... ## after designer generates it
...
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
def keyPressEvent(self, ev):
print "key press"
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
MainWindow = Window()
MainWindow.show()
sys.exit(app.exec_())

Resources