Context
I code with pyqt5 and python. Recently, I couldn't get autocompletion working for the objects inside the imported .ui > .py files from qtdesigner. I'd like to know how to get that autocompletion back on PyCharm 2019.
Code
from PyQt5 import uic
from PyQt5.QtWidgets import QWidget
someWidgetPath= os.path.dirname(os.path.realpath(__file__)) + '\\someWidgetUi.ui'
Ui_someWidget, QtBaseClass = uic.loadUiType(someWidgetPath)
class SomeNewWidget(QWidget, Ui_someWidget):
def __init__(self):
super(GraphManagerWidget, self).__init__()
self.setupUi()
self.XXX
There is no autocompletion on this XXX. In my .ui, I have a textEdit named te_name, but it doesn't appear. Thus, I always have to go back to my qtdesigner, lookup the name I gave the QObjects and then write it in the code. Sometimes, I find this time consuming.
Setup
Windows==10.0.1
Python==3.7.6
PyQt5==5.14.1
QtDesigner==5.11.1
PyCharm==2019.3.3
Related
I created UI using Qt Designer. Then I converted the ui file to a .py file (pyuic -x) - it works fine if launched directly. Then I tried to subclass my ui in a separate file to implement additional logic. And this is where things start to go wrong. Inheriting from QMainWindow and my Qt Designer file works OK with no issues, as expected. However, the moment I set any WindowFlag for my QMainWindow (any flag - I tried these: StaysOnTop, FramelessWindowHint) and run the file, the window appears and instantly disappears. The program continues to run in a console window, or as a PyCharm process, but the window is gone. It looks to me like it is getting out of scope - but why setting a simple flag would make any difference to the garbage collector? Could someone explain this behaviour?
Minimum code required to reproduce this phenomenon:
from ui import Ui_MainWindow
from PyQt5 import QtCore, QtWidgets, QtGui
import sys
class Logic(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.setupUi(self)
self.show()
# self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
# self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = Logic()
sys.exit(app.exec_())
The window should appear and stay on the screen until one (or more) of the flags are uncommented. I use Python 3.8 (32-bit) with PyQt5. Run environment provided by PyCharm. Windows 10.
From the documentation of setWindowFlags():
Note: This function calls setParent() when changing the flags for a window, causing the widget to be hidden. You must call show() to make the widget visible again..
So, just move self.show() after setting the flags, or call it from outside the __init__ (after the instance is created), which is the most common and suggested way to do so, as it's considered good practice to show a widget only after it has been instanciated.
I'm attempting to create a dialog which contains two child widgets: on the left side a QFileDialog instance so users can select files, and on the right side a separate widget which will be used to show a preview of the selected file if it is of a certain type.
The problem is that the dialog opens up and I can see the "preview" widget just fine, but the QFileDialog is not showing up at all.
This short example demonstrates my problem:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
app = QApplication([])
main_dialog = QDialog()
main_dialog.setWindowTitle('My Dialog')
layout = QHBoxLayout(main_dialog)
file_dialog = QFileDialog(main_dialog, Qt.Widget)
file_dialog.setOption(QFileDialog.DontUseNativeDialog)
layout.addWidget(file_dialog)
preview = QLabel('Preview', main_dialog)
layout.addWidget(preview)
main_dialog.show()
app.exec_()
Some things that I've tried:
Add file_dialog.show() before/after main_dialog.show(): this shows up the QFileDialog, but in a different window; I want the file dialog to appear inside main_dialog, not as a separate window;
Do not pass Qt.Widget to the QFileDialog constructor, to no effect;
Do not pass main_dialog as parent to QFileDialog, again no effect;
Change main_dialog to a QWidget just to see if it changed anything, it did not;
I've searched the docs but did not find a suitable solution.
Any hints? Also, suggestions on how to accomplish the task of allowing the user to select a file and display a preview of the file in the same window are welcome.
Context: this is a port of an old application written for Qt3. Qt3's QFileSystem dialog had this "preview" functionality built-in; I'm trying to reproduce the same functionality in Qt5.
Versions
Python 2.7
PyQt 5.5.1
I've also tried with Python 3.6 (from conda-forge) but obtained the same behavior.
You need to turn off the Qt.Dialog flag in the file dialog's windowFlags...
file_dialog.setWindowFlags(file_dialog.windowFlags() & ~Qt.Dialog)
Otherwise the QFileDialog will always be created as a top level window. Works for me anyway.
I am building a Gui in QtDesigner but i do not understand how i add a "dynamical property":
I try to add a QTable Widget but the Header of the Columns are to large (The Text is just 2 letter in the Columns).
For Space reasons in my Gui i just need them to be as big as the text is (or let us say 4 letters)
i found the
QHeaderView::ResizeToContents method but i do not know how to use it- is there a way to do this in QtDesigner?
I am new to this and i do not know how to change the code behind the Gui...
For PyQt, the main purpose of Qt Designer is to create the main GUI structure of your application. It only allows a subset of the available properties to be modified for any given widget, and it cannot be used to write the application's main logic.
Instead, the idea is to generate a python module from the ui file created by Qt Designer, and then import it into your application where you can do the remaining setup code, connect signals, write all the event handlers, etc.
Let's say you've created a ui file with Qt Designer and named it mainwindow.ui.
You would then generate the python module like this:
pyuic4 -o mainwindow_ui.py mainwindow.ui
Next, you would write a separate main.py script that imports the GUI classes from the generated module, and creates instances of them as needed.
So your main.py would look something like this:
from PyQt4 import QtCore, QtGui
from mainwindow_ui import Ui_MainWindow
class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
header = self.tableWidget.horizontalHeader()
header.setResizeMode(QtGui.QHeaderView.ResizeToContents)
...
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
The base-class here must be same as the top-level widget in Qt Designer (i.e. usually either QMainWindow, QDialog, or QWidget). Also, the objectName property of the top-level widget is used to generate the classname of the imported GUI class (with "Ui_" prepended to it). The example above assumes this was set to "MainWindow".
The objectName properties of all the other widgets will become attributes of the MainWindow class, so that they can be accessed easily in the rest of your code. Because of this, it's important that you always set the objectName properties to descriptive names (i.e. not "pushButton_1", "pushButton_2", etc).
I have created a GUI with Qt Designer and accessed it via
def loadUiWidget(uifilename, parent=None):
loader = QtUiTools.QUiLoader()
uifile = QtCore.QFile(uifilename)
uifile.open(QtCore.QFile.ReadOnly)
ui = loader.load(uifile, parent)
uifile.close()
return ui
MainWindow = loadUiWidget("form.ui")
MainWindow.show()
children = MainWindow.children()
button1 = MainWindow.QPushButton1
"children" does already contain the widgets "QPushButton1", "QTextBrowser1" created in the UI but shouldn't the be accessed by the recoursive findChildren() method?
What is an elegant way to access the widgets of the .ui File?
References:
Find correct instance,
Load .ui file
Since widget names in Qt Designer must be unique, the hierarchy (at least for getting references to the widgets) is flattened (with no risk of conflict), and so the best way is just to access them via:
loader = QtUiTools.QUiLoader()
ui = loader.load('filename.ui', parent)
my_widget = ui.my_widget_name
This would place a reference to the widget called 'my_widget_name' in Qt Designer in the variable my_widget.
I would say the above is the most pythonic way of accessing the widgets created when you load the .ui file.
There are two disadvantages of loading UI at run time:
overhead each time the program is run (actually, each time the loader is used)
lack of support of code completion and checking, since IDE doesn't know the code behind ui until the uifile has been loaded.
An alternative, assuming you are using the modern version of PySide called "Qt for Python", is to "compile" the .ui file to a Python class (see docs). For this, after saving filename.ui, execute
pyside2-uic filename.ui -o ui_mainwindow.py
while within your virtual environment, if any. The new class will be called Ui_MainWindow. Assuming you have a text_box widget in your UI, you can now access its properties and methods. Here is a full working example:
import sys
from PySide2.QtWidgets import QApplication, QMainWindow
from ui_mainwindow import Ui_MainWindow
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.text_box.setPlainText('test') # here we are addressing widget
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Notes:
pyside2-uic should be called after every change of the .ui file. This is a disadvantage of this approach in comparison to OP. It also means that you should either version-control both .ui and .py files for your UI, or somehow call uic during deployment.
The big advantage is that IDE like PyCharm has access to all widget methods and properties for autocompletion and code checking.
As of today, pyside2-uic creates non-PEP8 compliant code. However, as long as you give your widgets PEP8-compliant names, your own code will be OK.
I am a new Ubuntu user and want to do my coding using Python and incorporating Qt designer for my forms (interface). I open the designer and put up some controls on the forms or widgets but I get problems on how to include the form I made in my Python codes. I try using the Import style for my .ui but to no avail. Please help on how I should go about this issue. Here is what I have: Mwakenya is the .ui file I created on Qt designer.
from pyQt import *
from mwakenya.ui import *
class at(mwakenya):
def __init__(self, parent=None, name=None, fl=0):
mwakenya.__init__(self,parent,name,fl)
if __name__ == "__main__":
import sys
a = QApplication(sys.argv)
QObject.connect(a,SIGNAL("lastWindowClosed()"),a,SLOT("quit()"))
w = at()
a.setMainWidget(w)
w.show()
a.exec_loop()
You need to compile your .ui files, into python code.
You can do this with the pyuic command.
eg.
pyuic mwakenya.ui -o mwakenya_ui.py
You then import mwakenya_ui.py
See here for more information:
http://manpages.ubuntu.com/manpages/hardy/man1/pyuic4.1.html
Users of KDE should look for pykdeuic, which performs the same job.