Writing a custom QPushButton class in Python - python

I've recently started learning PyQt on my own and I've come in some trouble trying to write a custom class that inherits from QPushButton so I can adjust its attributes. I'm trying to pass a text as an argument whenever I initialize an object of this class. I am pretty sure there's something wrong with my init but I haven't found it yet.
Here is the code:
import sys
from PySide import QtGui, QtCore
class mainb(QtGui.QPushButton):
def __init__(Text,self, parent = None):
super().__init__(parent)
self.setupbt(Text)
def setupbt(self):
self.setFlat(True)
self.setText(Text)
self.setGeometry(200,100, 60, 35)
self.move(300,300)
print('chegu aqui')
self.setToolTip('Isso é muito maneiro <b>Artur</b>')
self.show()
class mainwindow(QtGui.QWidget):
def __init__(self , parent = None):
super().__init__()
self.setupgui()
def setupgui(self):
self.setToolTip('Oi <i>QWidget</i> widget')
self.resize(800,600)
self.setWindowTitle('Janela do Artur')
af = mainb("Bom dia",self)
self.show()
"""
btn = QtGui.QPushButton('Botão',self)
btn.clicked.connect(QtCore.QCoreApplication.instance().quit)
btn.resize(btn.sizeHint())
btn.move(300, 50)
"""
def main():
app = QtGui.QApplication(sys.argv)
ex = mainwindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

You are using super in wrong way, super must get a instance and another thing your first arg is Text, that's wrong that should be self. I fixed some more and the below code should work for you
import sys
from PySide import QtGui, QtCore
class mainb(QtGui.QPushButton):
def __init__(self, Text, parent = None):
super(mainb, self).__init__()
self.setupbt(Text)
def setupbt(self, Text):
self.setFlat(True)
self.setText(Text)
self.setGeometry(200,100, 60, 35)
self.move(300,300)
print('chegu aqui')
self.setToolTip('Isso muito maneiro <b>Artur</b>')
self.show()
class mainwindow(QtGui.QWidget):
def __init__(self , parent = None):
super(mainwindow, self).__init__()
self.setupgui()
def setupgui(self):
self.setToolTip('Oi <i>QWidget</i> widget')
self.resize(800,600)
self.setWindowTitle('Janela do Artur')
newLayout = QtGui.QHBoxLayout()
af = mainb("Bom dia",self)
newLayout.addWidget(af)
self.setLayout(newLayout)
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = mainwindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Your def setupbt(self) does not seem to take the text as argument. Try def setupbt(self, Text): instead.

Related

PyQt5 Access MainWindow from Another Window

I am newbie and in that project I am stuck at one point. How can I access functions in MainWindow class from another Window.
For example I need to access Main.list_refresh when Child_EditAccount.btn_EDIT_ACCOUNT_3.clicked . I tried something like signal & slot but doesn't work. I maked 3 different Window with pyQt Designer and I need to link the three together.
new.py
# Designs
from design import Ui_MainWindow
from design_addAccount import Ui_MainWindow_Add
from design_editAccount import Ui_MainWindow_Edit
# Modules
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import pyqtSignal, pyqtSlot
import sqlite3
con = sqlite3.connect('shorts.sqlite3')
cur = con.cursor()
class Main(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.account_process = AccountProcess()
self.ui.lst_accounts.itemClicked.connect(self.account_process.edit_account)
self.ui.btn_delete_account.clicked.connect(self.account_process.delete_account)
self.ui.btn_edit_account.clicked.connect(self.account_process.edit_account)
self.ui.btn_add_account.clicked.connect(self.account_process.add_account)
self.ui.btn_refresh.clicked.connect(self.list_refresh)
self.refresh_trigger = Child_EditAccount()
self.refresh_trigger.buttonClicked.connect(self.list_refresh)
def list_refresh(self):
self.ui.lst_accounts.clear()
for row in cur.execute("SELECT * FROM users"):
self.ui.lst_accounts.addItem('%s' % (str(row[3])))
class Child_AddAccount(QtWidgets.QMainWindow,Ui_MainWindow_Add):
def __init__(self, parent=None):
super(Child_AddAccount, self).__init__()
self.ui = Ui_MainWindow_Add()
self.ui.setupUi(self)
class Child_EditAccount(QtWidgets.QMainWindow,Ui_MainWindow_Edit):
buttonClicked = pyqtSignal()
def __init__(self, parent=None):
super(Child_EditAccount, self).__init__()
self.ui = Ui_MainWindow_Edit()
self.ui.setupUi(self)
def edit_infos(self, username, password, nickname, id):
self.id = id
self.ui.txtBox_username_3.insert(username)
self.ui.txtBox_password_3.insert(password)
self.ui.txtBox_nickname_3.insert(nickname)
self.ui.btn_EDIT_ACCOUNT_3.clicked.connect(self.update_by_id)
def update_by_id(self):
cur.execute('UPDATE users SET username="%s", password="%s", nickname="%s" WHERE id=%s' % (self.ui.txtBox_username_3.text(), self.ui.txtBox_password_3.text(), self.ui.txtBox_nickname_3.text(), self.id))
con.commit()
self.buttonClicked.emit()
class AccountProcess(QtCore.QObject):
def add_account(self):
self.child_add = Child_AddAccount()
self.child_add.show()
print('Pressed edit button')
def delete_account(self):
print('Pressed delete button')
def edit_account(self, item):
self.child_edit = Child_EditAccount()
for i in cur.execute(f"SELECT * FROM users WHERE nickname=\"{item.text()}\";"):
self.child_edit.edit_infos(str(i[1]), str(i[2]), str(i[3]), str(i[0]))
self.child_edit.show()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
You can use a pyqtSignal to do what you want.
in the Child_EditAccount class add a pyqtsignal
class Child_EditAccount(QtWidgets.QMainWindow,Ui_MainWindow_Add):
buttonClicked = pyqtSignal()
def __init__(self, parent=None):
before the __init__, then when you need to trigger the function use
buttonClicked.emit()
in the function where the button is used in the Child_EditAccount class
Then in the main window, you can create a connection to a function via the pyqtsignal
self.Child_EditAccount.buttonClicked.connect(self.myfunction)
in the __init__ of the main class. where self.Child_EditAccount is the instance of your Child_EditAccount class and self.function is the function you want to trigger Main.list_refresh
You can also create a signal from QtDesigner itself when you create the Ui_MainWindow_Edit
https://doc.qt.io/qt-5/designer-connection-mode.html
be carefull, Child_EditAccount inherite from Ui_MainWindow_Add instead of Ui_MainWindow_Edit probably.
____
what you can also do is link the sigal of the button directly in the main program as in this little example
# Modules
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import pyqtSignal, pyqtSlot
class Main2(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Main2, self).__init__()
self.centralWidget = QtWidgets.QWidget()
self.setCentralWidget(self.centralWidget)
self.but= QtWidgets.QPushButton('tdvfdbt')
self.l = QtWidgets.QHBoxLayout()
self.l.addWidget(self.but)
self.centralWidget.setLayout(self.l)
class Main(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__()
self.win = Main2()
self.a = self.win.show()
self.win.but.clicked.connect(self.myfunction)
def myfunction(self):
print('called from sub window')
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
ex = Main(app)
ex.setWindowTitle('Model micro GUI')
# ex.showMaximized()
ex.show()
sys.exit(app.exec())
if you know the name of the button widget of the Child_EditAccount class you can link it via
self.Child_EditAccount.btn_EDIT_ACCOUNT_3.clicked.connect(self.myfunction)
##______
Put the pystsignal in the AccountProcess class
class AccountProcess(QtCore.QObject):
buttonClicked = pyqtSignal()
def add_account(self):
self.child_add = Child_AddAccount()
self.child_add.show()
print('Pressed edit button')
def delete_account(self):
print('Pressed delete button')
def edit_account(self, item):
self.child_edit = Child_EditAccount()
for i in cur.execute(f"SELECT * FROM users WHERE nickname=\"{item.text()}\";"):
self.child_edit.edit_infos(str(i[1]), str(i[2]), str(i[3]), str(i[0]))
self.child_edit.buttonClicked.connect(self.EmitAgain)
self.child_edit.show()
def EmitAgain(self):
self.buttonClicked.emit()
Then use it in the main class
class Main(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.account_process = AccountProcess()
self.account_process.buttonClicked.connect(self.list_refresh)

mouseMoveEvent() while cursor is on button

I have to activate some function, when the cursor is moving. So, I used self.setMouseTracking(True) in MainWidget. But in this way mouseMoveEvent() works only when there is an empty form under cursor. I tried to create another widget over main, but it doesnt work at all.
class ClickButton(QPushButton):
def __init__(self, text, window):
...
def run(self):
...
class Window(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(0, 0, 1000, 1000)
self.setMouseTracking(True)
self.clickers = [ClickButton('OK', self) for i in range(8)]
def mouseMoveEvent(self, ev):
for e in self.clickers:
e.run()
Whats to do?
If you want to detect the position of the mouse even when the mouse is on top of a child, a possible option is to use an event filter.
from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
w_ = QtWidgets.QWidget()
lay_w = QtWidgets.QHBoxLayout(w_)
for c in (QtWidgets.QPushButton(), QtWidgets.QLineEdit()):
lay_w.addWidget(c)
lay = QtWidgets.QVBoxLayout(self)
for w in (QtWidgets.QPushButton(), QtWidgets.QLineEdit(), QtWidgets.QTextEdit(), w_):
lay.addWidget(w)
for ws in self.findChildren(QtWidgets.QWidget) + [self]:
ws.setMouseTracking(True)
ws.installEventFilter(self)
def eventFilter(self, obj, event):
if event.type() == QtCore.QEvent.MouseMove:
p_respect_to_window = self.mapFromGlobal(obj.mapToGlobal(event.pos()))
print(p_respect_to_window)
return super(Widget, self).eventFilter(obj, event)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
On the other hand if you only want to do it in only one type of custom widget it is better to overwrite the mouseMoveEvent method of the custom widget:
from PyQt5 import QtCore, QtGui, QtWidgets
class ClickButton(QtWidgets.QPushButton):
def __init__(self, text, parent=None):
super(ClickButton, self).__init__(text=text, parent=parent)
self.setMouseTracking(True)
def mouseMoveEvent(self, event):
self.run()
super(ClickButton, self).mouseMoveEvent(event)
def run(self):
print("call to run function in button{} and time: {}".format(self.text(),
QtCore.QDateTime.currentDateTime().toString()))
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
lay = QtWidgets.QVBoxLayout(self)
for i in range(10):
w = ClickButton(str(i), self)
lay.addWidget(w)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())

TypeError: check() missing 1 required positional argument: 'theText'

I'm making a small PyQt4 application and so far I have this:
import sys
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.initUi()
def initUi(self):
self.setFixedSize(500, 300)
self.text = QtGui.QLabel('Text to be changed')
self.text2 = QtGui.QLabel('Also to be changed')
self.textCheckBox = QtGui.QCheckBox()
self.textCheckBox.stateChanged.connect(self.check(self.text))
self.show()
def check(self, state, theText):
if state == QtCore.Qt.Checked:
theText.setStyleSheet("color: pink")
else:
theText.setStyleSheet("color: black")
def main():
q = QtGui.QApplication(sys.argv)
w = Window()
sys.exit(q.exec())
if __name__=='__main__':
main()
The problem is, my .connect line doesn't seem to want to recognize the parameter I pass into it and I'm not sure why. I can't reference the text directly in the function as I would like to pass many QLabel arguments to it hence I made a theText parameter. I'd appreciate any help.
Version that works without parameters:
import sys
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.initUi()
def initUi(self):
self.setFixedSize(500, 300)
self.text = QtGui.QLabel('Text to be changed')
self.text2 = QtGui.QLabel('Also to be changed')
self.textCheckBox = QtGui.QCheckBox()
self.textCheckBox.stateChanged.connect(self.check)
self.hbox = QtGui.QHBoxLayout()
self.hbox.addWidget(self.text)
self.hbox.addWidget(self.textCheckBox)
self.setLayout(self.hbox)
self.show()
def check(self, state):
if state == QtCore.Qt.Checked:
self.text.setStyleSheet("color: pink")
else:
self.text.setStyleSheet("color: black")
def main():
q = QtGui.QApplication(sys.argv)
w = Window()
sys.exit(q.exec())
if __name__=='__main__':
main()
import sys
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.initUi()
def initUi(self):
self.setFixedSize(500, 300)
self.text = QtGui.QLabel('Text to be changed')
self.text2 = QtGui.QLabel('Also to be changed')
self.textCheckBox = QtGui.QCheckBox()
test = self.textCheckBox.checkState()
self.textCheckBox.stateChanged.connect(lambda: self.check(self.textCheckBox.checkState(), self.text))
self.hbox = QtGui.QHBoxLayout()
self.hbox.addWidget(self.text)
self.hbox.addWidget(self.textCheckBox)
self.setLayout(self.hbox)
self.show()
def check(self, state, theText):
if state == QtCore.Qt.Checked:
self.setWindowTitle("test")
else:
theText.setStyleSheet("color: black")
def main():
q = QtGui.QApplication(sys.argv)
w = Window()
sys.exit(q.exec())
if __name__=='__main__':
main()
Seem to have fixed it. Not too sure why it works though.

QtCore.SIGNALS not working on my code

Can someone me explane how should like my code, or what I'm doing wrong ?
I want to use button 'btn_run' to run 'view_splash' function. But somethink going wrong, but 'view_splash' won't start. It show me no errors.
import sys
from PyQt4 import QtGui, QtCore
import time
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(500, 150, 500, 600)
self.setWindowTitle('Test GUI')
self.threadclass = AThread()
self.connect(self.threadclass, QtCore.SIGNAL("view_splash()"), self.view_splash)
self.home()
def home(self):
btn_run = QtGui.QPushButton("Run", self)
self.threadclass = AThread()
btn_run.clicked.connect(self.threadclass.start)
btn_run.resize(120, 40)
btn_run.move(190, 540)
self.show()
def view_splash(self):
print('test')
label = QLabel("<font color=red size=10<b>" + "SPLASH" + "</b></font>")
label.setWindowFlags(Qt.SplashScreen | Qt.WindowStaysOnTopHint)
label.show()
QtCore.QTimer.singleShot(5000, label.close)
class AThread(QtCore.QThread):
def __init__(self):
super(AThread, self).__init__()
def run(self):
print(1)
print(2)
time.sleep(5)
print(3)
print(4)
self.emit(QtCore.SIGNAL("view_splash()"))
app = QtGui.QApplication(sys.argv)
GUI = Window()
sys.exit(app.exec_())
You need to create and connect the signals differently.
class AThread(QtCore.QThread):
view_splash = QtCore.pyqtSignal()
def run(self):
...
self.view_splash.emit()
class Window(QtGui.QMainWindow):
def __init__(self):
...
self.threadclass.view_splash.connect(self.view_splash)

PYQT 4: How can i call a GUI Function in another class?

I will make 2 examples to explain it
I created a Button that when i click it, it shows a message in the TextEdit Widget (in this case it shows "A string").
If i do that in the same class of the GUI, i have no problems:
from PyQt4.QtGui import *
import sys
class Aplicacion(QWidget):
def __init__(self, parent=None):
super(Aplicacion, self).__init__()
vbox = QVBoxLayout(self)
self.textedit = QTextEdit('')
self.button = QPushButton("Do anything")
#Layouts
vbox.addWidget(self.textedit)
vbox.addWidget(self.button)
#Connections
self.button.clicked.connect(self.aFunction)
def aFunction(self):
self.textedit.append("A string")
app = QApplication(sys.argv)
test = Aplicacion()
test.show()
app.exec_()
It works fine: http://puu.sh/kpEHC.png
But when i am trying to do the same in another class or function i get this error:
from PyQt4.QtGui import *
import sys
def appendAnything(self):
Aplicacion().textedit.append("test") # HERE IS THE ERROR
class Aplicacion(QWidget):
def __init__(self, parent=None):
super(Aplicacion, self).__init__()
vbox = QVBoxLayout(self)
self.textedit = QTextEdit('')
self.button = QPushButton("Do anything")
#Layouts
vbox.addWidget(self.textedit)
vbox.addWidget(self.button)
#Connections
self.button.clicked.connect(appendAnything)
def aFunction(self):
self.textedit.append("A string")
app = QApplication(sys.argv)
test = Aplicacion()
test.show()
app.exec_()
Error:
Aplicacion().textedit.append("test") # HERE IS THE ERROR
RuntimeError: wrapped C/C++ object of type QTextEdit has been deleted
Image: http://puu.sh/kpETO.png
Thanks and sorry for my english
This happens because you are creating a new Aplicacion instances inside the function scope and it gets destroyed as soon as your code goes back to the main loop since you don't keep any reference of this new instance. Also I don't understand why you are creating a new Aplicacion instance: I think you should probably pass a reference of your main widget to the function. An easy (non thread safe) way to do that is to use partial:
from PyQt4.QtGui import *
from functools import partial
import sys
def appendAnything(self, app):
app.textedit.append("test")
class Aplicacion(QWidget):
def __init__(self, parent=None):
super(Aplicacion, self).__init__()
vbox = QVBoxLayout(self)
self.textedit = QTextEdit('')
self.button = QPushButton("Do anything")
#Layouts
vbox.addWidget(self.textedit)
vbox.addWidget(self.button)
#Connections
self.button.clicked.connect(partial(appendAnything, app=self))
def aFunction(self):
self.textedit.append("A string")
if __name__ == '__main__':
app = QApplication(sys.argv)
test = Aplicacion()
test.show()
app.exec_()

Categories

Resources