PyQt6 Accessing UI Object Attributes - python

I'm trying to create a simple GUI in Python using PyQt6 and Qt Designer.
I've already made the .ui file, and am able to load it properly and have it shown when running the code.
I can't, however, seem able to access any of the objects, i.e buttons and such.
When I print out the children of the AppWindow object I do see all of them listed, but I can't change their attributes via self.button (inside the class init function)- it says 'unresolved attribute reference'.
To my understanding it's supposed to be something trivial, so I'm not quite sure what I had managed to get wrong here.
Would appreciate any help since I'm stumped.
Thank you.
Here's my code-
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout
from PyQt6.QtCore import Qt
from PyQt6 import uic
class AppWindow(QWidget):
def __init__(self):
super().__init__()
uic.loadUi('gui.ui', self)
self.setWindowTitle('API-SF App')
if __name__ == '__main__':
app = QApplication(sys.argv)
app_window = AppWindow()
app_window.show()
sys.exit(app.exec())

Related

How to load a Qt Designer file (.ui) in a QWizardPage using PySide2

I want to design my QWizardPages in Qt Designer and I want to load them into my Python program with PySide2. Previously I have been using PyQt5 without any problems but making the switch to PySide2 seems harder then expected.
The problem I am facing is that when I am adding a QWizardPage to my QWizard , the page is indeed added to the Wizard, but also an other (empty) page is added. I'm not able to find what I'm doing wrong so I was wondering if someone can have a look.
I have tried to add the pages with both the functions addPage() and setPage(), but they give the same results. What I also noticed is that when I explicitely set the Title of the page with setTitle(), the empty (unwanted) page gets this title, but not the page I designed in Qt Designer.
import os
import sys
from PySide2.QtWidgets import QWizard, QWizardPage, QApplication
from PySide2.QtCore import QFile
from PySide2.QtUiTools import QUiLoader
from enum import Enum
class MyWizard(QWizard):
def __init__(self):
super().__init__()
self.setPage(PageNumbers.page_one.value, PageOne(self))
class PageOne(QWizardPage):
def __init__(self, parent):
super().__init__(parent)
ui_file = os.path.join(__file__, '..', 'pageOne.ui')
file = QFile(ui_file)
file.open(QFile.ReadOnly)
loader = QUiLoader()
loader.load(file, parent)
file.close()
self.setTitle("This is another test Title")
class PageNumbers(Enum):
page_one = 1
if __name__ == '__main__':
app = QApplication(sys.argv)
wizard = MyWizard()
wizard.show()
app.exec_()
What I would expect is to have just one QWizardPage showing up with directly the Finish button. Instead I get two QWizardPages as shown in this image:
Can someone tell me what's going on?
(I get the expected result using PyQt5 with the following code: https://pastebin.com/6W2sx9M1)
The developers of PyQt implement functions to be able to create classes based on the .ui that is not implemented in Qt by default (Qt/C++ uses the MOC to do this work), but in the case of PySide2-Qt for python it does not implement it, only has the QUiLoader class that allows to create a widget based on the .ui unlike PyQt that allows filling a class.
In conclusion there is no equivalent in PySide2 of the loadUi function so you can not implement the same logic. PySide2 is not PyQt5, there are own equivalences since they use the same base but they have implementations, limitations and advantages.
Going to the practical problem, considering that the .ui is next to the .py the solution is the following:
import os
import sys
from PySide2 import QtCore, QtWidgets, QtUiTools
from enum import Enum
class PageNumbers(Enum):
page_one = 0
class MyWizard(QtWidgets.QWizard):
def __init__(self):
super().__init__()
ui_file = os.path.join(os.path.dirname(os.path.abspath(__file__)) ,'PageOne.ui')
page_one = create_widget(ui_file, self)
self.setPage(PageNumbers.page_one.value, page_one)
def create_widget(filename, parent=None):
file = QtCore.QFile(filename)
if not file.open(QtCore.QFile.ReadOnly):
return
loader = QtUiTools.QUiLoader()
widget = loader.load(file, parent)
return widget
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
wizard = MyWizard()
wizard.show()
sys.exit(app.exec_())

pyqt5, Receiving AttributeError: 'QMainWindow' object has no attribute 'browseSlot'

I'm learning pyqt5, and specifically how to use it with the QT Designer. I'm sort of following the turorial HERE. However in this tutorial they are converting the XML interface to Python code with pyuic5, while I'm trying to import it dynamically with uic.loadUi("myui.ui"). In the tutorial we define a slot with the signals and slot editor named " browseSlot".
When I try to run/compile, at the line
dlg = uic.loadUi("myui.ui")
I get the error:
AttributeError: 'QMainWindow' object has no attribute 'browseSlot'
I think what's going on is that QT Designer connects a signal to the slot 'browseSlot' but because a 'browseSlot' method isn't defined in the myui.ui, the error is thrown, because there is no way for the interpreter to know I'm referring to a method that is outside the UI interface file. (In this case, in the module that loads the interface). As far as I can tell QT Designer only lets me connect signals to slots, not define a whole new one. I think that way this is handled in other frameworks is that there will be an abstract method that needs over riding. So what can I do in this situation to make it work?
from PyQt5 import QtCore, QtGui, QtWidgets, uic
from PyQt5.QtCore import QObject, pyqtSlot
import sys
app = QtWidgets.QApplication([])
dlg = uic.loadUi("myui.ui")
#pyqtSlot
def returnPressedSlot():
pass
#pyqtSlot
def writeDocSlot():
pass
#pyQt
def browseSlot():
pass
dlg.show()
sys.exit(app.exec())
The slots belong to the class that is used returns loadUi(), they are not any functions since they do not magically not connect them, if you want to use loadUi() and implement these methods you must inherit from the class corresponding to the template that you used, in the example of the link Main Window was used so it must be inherited from QMainWindow:
from PyQt5 import QtCore, QtGui, QtWidgets, uic
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
uic.loadUi("mainwindow.ui", self)
#QtCore.pyqtSlot()
def returnPressedSlot():
pass
#QtCore.pyqtSlot()
def writeDocSlot():
pass
#QtCore.pyqtSlot()
def browseSlot():
pass
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
try this out
from PyQt5 import QtWidgets, uic
app = QtWidgets.QApplication([])
form = uic.loadUi("login.ui")
form2.show()
app.exec()
the above python code should display your gui app properly as long as you have install PyQt5 and PyQt5-tools,if you haven't then open CMD and typeenter code here "pip install PyQt5" and click enter.once installation is done type "pip install PyQt5-tools" then you are good to go

Add Custom Widget to listWidget on pyqt5

I used Qt Designer to make two .ui files, one is the Main Window of my application, and the second is a custom widget I made. My idea was to fill a listWidget on my Main application with this custom Widget to display data.
I made this code, which compiles without problem but it does not show the customWidget on the List when it runs
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QWidget, QAction, QTabWidget,QVBoxLayout,QDialog
from PyQt5 import QtCore, QtGui, QtWidgets
from mainwindowReclamo import Ui_MainWindow
from widgetReclamos import Ui_Form
#Custom Widget*
class WidgetReclamo(QWidget, Ui_Form):
"""docstring for ClassName"""
def __init__(self,*args,**kwargs):
QWidget.__init__(self,*args,**kwargs)
self.setupUi(self)
print("I am Alive")
#My Main Program*
class ProgramaReclamos(QMainWindow, Ui_MainWindow):
def __init__(self,*args,**kwargs):
QMainWindow.__init__(self,*args,**kwargs)
self.setupUi(self)
#I create an Item*
Item = QtWidgets.QListWidgetItem(self.listWidget)
#I create a custom widget*
Item_Widget = WidgetReclamo()
#I set the Size from the Item to the same of the widget*
Item.setSizeHint(Item_Widget.sizeHint())
#I add it to the list*
self.listWidget.addItem(Item)
self.listWidget.setItemWidget(Item, Item_Widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
prog = ProgramaReclamos()
prog.show()
sys.exit(app.exec_())
I saw some questions online wich their answer were for PyQt4 and they said something about using a Layout for the Widget, but I don´t understand if I have to make one becouse the widget was made in the .ui file
As EYLLANESC said on the comment:
Change Item.setSizeHint(Item_Widget.sizeHint()) to Item.setSizeHint(Item_Widget.size()) – eyllanesc
Thank you !

Detect Ctrl+S ion QTextedit?

So, I'm making a QTextEdit that edits a text file. I got the loading and saving working fine with buttons. But I got the habit of pressing Ctrl+S to save every time I paste something into the textedit because I used that in Notepad before. So I've been trying to implement it. But I can't wrap my head around how to detect and execute my save function. Lets call it savetext.
I've been going around trying to get keyPressEvent to work, but I just don't understand how it works. So I've been pretty helpless in trying to learn it.
My heavily simplified code looks like this:
class GUI(QProcess):
def init etc...
"Button creations and connect to save/load function"
self.textedit=QTextEdit()
def savetext(self):
code
def loadtext(self):
code
Now, how do I detect a key combination being detected in the QTextEdit, or anywhere in my program for that matter, and cause it to do savetext? In my case, Ctrl+S, though I'd just love a general explanation so I could apply it to any combo.
Use QShortcut and QKeySequence
from PyQt5.QtWidgets import QApplication, QTextEdit, QShortcut
from PyQt5.QtGui import QKeySequence
import sys
def slot():
print("Ctrl+S")
app = QApplication(sys.argv)
textedit=QTextEdit()
shortcut = QShortcut(QKeySequence("Ctrl+S"), textedit)
shortcut.activated.connect(slot)
textedit.show()
sys.exit(app.exec_())
You can probably use QShortcut, and right now it will activate only when textedit in focus. If you want to change the behavior please take a look here
Here is a example
import sys
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
layout = QtGui.QVBoxLayout(self)
self.edit = QtGui.QTextEdit()
layout.addWidget(self.edit)
self.button = QtGui.QPushButton('Test')
layout.addWidget(self.button)
foo = QtGui.QShortcut(QtGui.QKeySequence("Ctrl+S"), self.edit, self.saveCall, context=QtCore.Qt.WidgetShortcut)
def saveCall(self):
self.edit.append('Please save me')
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())

PyQt5 & Qt Designer: why the second form displays a bad thing?

I can't make form1 to make parent object like it needs to be.
And all content in second form align to left-top corner and i have no way to make it work fine. May be someone know what i can do with this. Thank you!
How it looks in Qt Designer:
But how it looks really:
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import QMainWindow, QApplication
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# Set up the user interface from Designer.
uic.loadUi("mw.ui", self)
uic.loadUi("form1.ui", self.mn_general)
# Connect up the buttons.
self.pushButton.clicked.connect(self.BtnClck)
self.show()
def BtnClck(self):
print('Hello StackOverflow')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainWindow()
sys.exit(app.exec_())

Categories

Resources