Following the examples outlined in "Create simple GUI" I have tried to create Custom Widget, but nothing seems to by shown. It seems to be the simplest widget that I can imagine but still something is missing and I have no idea what.
from PyQt5.QtWidgets import *
import sys
class customWidget(QWidget):
def __init__(self, *args, **kwargs):
super(customWidget, self).__init__(*args, **kwargs)
layout = QHBoxLayout()
label = QLabel("Que chinga")
layout.addWidget(label)
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("Esta locura")
label = customWidget()
self.setCentralWidget(label)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
Do any of the following in the __init__ of customWidget (they are the conceptually the same thing):
add self.setLayout(layout) after creating the layout;
change layout = QHBoxLayout() to layout = QHBoxLayout(self);
The reason is that you're not setting the layout for the widget, so the QLabel has no parent and won't be shown on its own.
In practice, the customWidget instance could know anything about those objects, so there's no reason for which it should show them.
I also suggest you to:
read about classes and instances: while it's not directly related to this issue, it has lots of aspects in common, since the parenthood relation of Qt objects (such as QWidget subclasses) is closely related to the OOP aspects of instances.
always use capitalized names for classes (CustomWidget, not customWidget), as lower cased names should only be used for variable and function names.
Related
I have a main window created in one python module. This module also contains a class definition used to create an object called my_settings.
I also have a separate module which creates a another window (which should be in a different module for various reasons). This window allows various inputs such as opening a file and storing some settings once buttons are clicked blaa blaa.
What I want to do is then amend the attributes of my_setttings. A simplified version of the code is:
MAIN MODULE
class MainWindow(QMainWindow):
def __init__(self,parent=None):
super(MainWindow, self).__init__(parent)
QMainWindow.__init__(self)
uic.loadUi(self.some_directory + "arc_custom_main.ui", self)
self.some_button.clicked.connect(self.open_some_widget)
def open_some_widget(self):
widget = widget_in_other_module(self)
widget_in_other_module.exec_()
app = QApplication(sys.argv)
my_settings=settings()
_mainWindow = MainWindow()
_mainWindow.show()
SEPERATE MODULE
class widget_in_other_module(QDialog):
def __init__(self, parent):
my_settings.temppath = my_settings.OutputDir
QDialog.__init__(self)
self.parent = parent
my_settings.some_attribute= foo
uic.loadUi("some.ui", self)
self.pushButtonOpenMain.clicked.connect(self.openMain)
def openMain(self):
my_settings.some_other_attibute=bar
The problem I have is that I can't find a way to be able to access my_settings in the openMain method of widget_in_other_module. I'm a bit of a newbe to qt and can't for the life of me work out where I should pass my_settings. For various reasons I need all the functionality of widget_in_other_module to be outside of the main module (mostly to do with readability and future planed changes to the main module). I've tried as much as I can think of e.g. including it as a parameter in the line self.pushButtonOpenMain.clicked.connect(self.openMain,my_settings) but this doesn't seem to be allowed. Am I missing something basic here?
Instantiate settings variable in separate module and import this varable where you need it. It could be object of a class or just dictionary.
storage.py
class Settings:
def __init__(self):
print("Settings")
my_settings = Settings()
MainWindow.py
from PyQt5.QtWidgets import QMainWindow, QApplication
import sys
from Widget import Widget
from storage import my_settings
class MainWindow(QMainWindow):
def __init__(self,parent=None):
super(MainWindow, self).__init__(parent)
QMainWindow.__init__(self)
self.open_some_widget()
def open_some_widget(self):
widget = Widget()
widget.show()
widget.test()
self._widget = widget
my_settings.foo = 10
app = QApplication(sys.argv)
_mainWindow = MainWindow()
_mainWindow.show()
app.exec_()
Widget.py
from PyQt5.QtWidgets import QWidget
from storage import my_settings
class Widget(QWidget):
def test(self):
print(my_settings.foo)
I'm using Qt Designer for design GUI to use in python, after designing my desired UI in Qt Designer, convert it to python code and then I changed generated code to do some action in my python code, but if I changed the UI with Qt Designer and convert it to python code again, I lost my previous changes on my code.
how can I solve the problem?
can we Spreading a Class Over Multiple Files in python to write code in other files?
To avoid having these problems it is advisable not to modify this file but to create a new file where we implement a class that uses that design.
For example, suppose you have used the MainWindow template in the design.ui file, then convert it to Ui_Design.py like to the following structure:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
[...]
def retranslateUi(self, MainWindow):
[...]
Then we will create a new file that we will call logic.py where we will create the file that handles the logic and that uses the previous design:
class Logic(QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
So even if you modify the design and generate the file again .py you will not have to modify the file of the logic.
To generalize the idea we must have the following rules but for this the logic class must have the following structure:
class Logic(PyQtClass, DesignClass):
def __init__(self, *args, **kwargs):
PyQtClass.__init__(self, *args, **kwargs)
self.setupUi(self)
PyQtClass: This class depends on the design chosen.
Template PyQtClass
─────────────────────────────────────────────
Main Window QMainWindow
Widget QWidget
Dialog with Buttons Bottom QDialog
Dialog with Buttons Right QDialog
Dialog with Without Buttons QDialog
DesignClass: The name of the class that appears in your design.
The advantage of this implementation is that you can implement all the logic since it is a widget, for example we will implement the solution closing pyqt messageBox with closeevent of the parent window :
class Logic(QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
def closeEvent(self, event):
answer = QtWidgets.QMessageBox.question(
self,
'Are you sure you want to quit ?',
'Task is in progress !',
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
if answer == QtWidgets.QMessageBox.Yes:
event.accept()
else:
event.ignore()
The easiest way is to use the *.ui file directly in the python code, you don't need convert to *.py file every time you change the ui.
you can use this pseudo code in your project.
# imports
from PyQt5 import uic
# load ui file
baseUIClass, baseUIWidget = uic.loadUiType("MainGui.ui")
# use loaded ui file in the logic class
class Logic(baseUIWidget, baseUIClass):
def __init__(self, parent=None):
super(Logic, self).__init__(parent)
self.setupUi(self)
.
.
.
.
def main():
app = QtWidgets.QApplication(sys.argv)
ui = Logic(None)
ui.showMaximized()
sys.exit(app.exec_())
I'm tired about looking for the methods to deal with widgets within python class (Python 2.7 & PyQt4) who load file.ui (GUI QTDesigner)
CODE
form_class = uic.loadUiType("MyPythonProgram.ui")[0]
class MyWindowClass(QtGui.QMainWindow, form_class):
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.btn_buscar.clicked.connect(self.buscar)
def addingResultsToQListView(self):
for item in SomeList:
self.listView.addItem(item) ###It's not correct, but cannot find the right one
def onListItemClicked():
getItem = listView.currentItem().text() ###It's not correct, but cannot find the right one
def buscar(self):
getEditText = self.textEdit.toPlainText()
### Don't know how to do this function. I want to get the edittext to search on some website and retrieve the results into a list. then the list will be added to QlistView (just found C++ methods, not for python)
#Finally
getEditText = '' ###After click on 'btn_buscar', want to clear this field
app = QtGui.QApplication(sys.argv)
MyWindow = MyWindowClass(None)
MyWindow.show()
app.exec_()
It could be helper to get some DOC, or some help about making python apps hybrid (Android if its possible), keeping .ui and .py layers separately as I'm trying to show you.
This is my .ui for more information:
QUESTION'
How could I bind python functions with elements on .ui? I was trying too much methods but didn't find the right one. Need to know how to deal with QlistView and Qedittext... Thanks
This is the way I do it: separate the classes between construction (loading) of the UI and changing its content.
form_class = uic.loadUiType("MyPythonProgram.ui")[0]
class MyWindowClass(QtGui.QMainWindow, form_class):
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
class myGui:
def __init__(self):
self.gui = MyWindowClass() # that's the trick!
# self.addindResultsToQListView() # doesn't work, because I don't have your list items
self.gui.btn_buscar.clicked.connect(self.buscar)
self.editText = None
def show(self):
self.gui.show()
def addingResultsToQListView(self):
for item in SomeList: # you need to specify this `list` before this works!
self.gui.listView.addItems(item)
def buscar(self):
self.editText = self.gui.textEdit.text()
self.gui.textEdit.setText("")
app = QtGui.QApplication(sys.argv)
MyWindow = MyGui()
MyWindow.show()
app.exec_()
The trick is to reference the MyWindowClass, which is the constructor of your gui and hence the GUI itself, as an object within the class that controls the content of your GUI (myGui).
You call myGui on toplevel which then calls MyWindowClass as the object self.gui. From then on, whenever you want to address something in your GUI you name it self.gui. and add the QObject.
I also tried to understand what you want to do for the pushBotton. The content of your TextEdit (in PyQt they are called lineEdit btw) is stored in the variable self.editText which is initialized as None. Afterwards, the lineEdit is cleared from the user content.
I have a simple project with the following classes
class MainWindow(QMainWindow)
class Home(QWidget)
class Login(QWidget)
All I want is to be able to nest the QWidget classes (make them children of the QMainWindow) and display them INSIDE the MainWindow. I can't seam to figure out how to make the QWidgets "appear" after I've called them in the MainWindow.
Code is bellow:
import sys
from gui.MainWindow import Ui_MainWindow
from gui.home import Ui_Home
from gui.login import Ui_Login
from PyQt4.QtGui import QMainWindow, QApplication, QWidget
class Home(QWidget, Ui_Home):
def __init__(self):
QWidget.__init__(self)
self.setupUi(self)
class Login(QWidget, Ui_Login):
def __init__(self):
QWidget.__init__(self)
self.setupUi(self)
class MainWindow(QMainWindow,Ui_MainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
#INSERT pushButton.click to go to HOME here
#INSERT pushButton.click to go to LOGIN here
def setHome(self):
self.label_Screen.setText("HOME")
self.mainwidget = Home()
#NEEDS SOMETHING HERE
def setLogin(self):
self.label_Screen.setText("LOGIN")
self.mainwidget = Login()
#NEEDS SOMETHING HERE
if __name__ == '__main__':
app = QApplication(sys.argv)
Main = MainWindow()
Main.show()
sys.exit(app.exec_())
I think I just need something where I've tagged "#NEEDS SOMETHING HERE", but I'm not sure what!
Cheers!
RESOLVED: thanks to kh25
Just had to add a layout to the QMainWindow and change the setHome to this:
def setHome(self):
self.label_Screen.setText("HOME")
self.currentScreen = Home()
self.layout.addWidget(self.currentScreen)
self.setLayout(self.layout)
The equivalent should be done for the setLogin method also.
You need to create a layout and add the widgets to this layout first. There are various types of layout. Read here:
http://doc.qt.io/qt-4.8/layout.html
For a simple case like yours I'd suggest either using a QHBoxLayout or QVBoxLayout.
Declare this layout. Call addWidget() on the layout for each of the Login and Home widgets and then call setLayout() on the QMainWindow.
I would like to create a widget that has a child widget that I can dynamically change. Here is what I tried:
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class Widget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setLayout(QVBoxLayout())
self.child = QLabel("foo", self)
self.layout().addWidget(self.child)
def update(self):
self.layout().removeWidget(self.child)
self.child = QLabel("bar", self)
self.layout().addWidget(self.child)
app = QApplication(sys.argv)
widget = Widget()
widget.show()
widget.update()
app.exec_()
The problem is that this doesn't actually remove the "foo" label visually. It is still rendered on top of "bar". Screenshot of the problem. How do I remove the old widget so that only the new widget is shown?
I know that I can change the text property of the label. This is not what I want in my application, I need to change the actual widget (to a different widget type).
removeWidget() only removes the item from the layout, it doesn't delete it. You can delete the child widget by calling setParent(None).
def update(self):
self.layout().removeWidget(self.child)
self.child.setParent(None)
self.child = QLabel("bar", self)
self.layout().addWidget(self.child)