Import .ui during definition of QMainWindow - python

i'm trying to load a "mw.ui" file (made with Qt creator) as the design to be used on my Main Window.
I successfully load a class with:
from pyqtgraph.Qt import QtGui, QtCore, uic
mw = uic.loadUi("mw.ui")
but i can't define my class since I already have my object built. I tried to compile the mw.py during execution with
uic.compileUi("mw.ui", "mw.py")
but i have the following error:
Traceback (most recent call last):
File "myFile.py", line 26, in
uic.compileUi("mw.ui", "mw.py")
File "C:\Users\giovanni\AppData\Local\Programs\Python\Python36\lib\site-packages\PyQt5\uic__init__.py", line 162, in compileUi
pyfile.write(_header % (uifname, PYQT_VERSION_STR))
AttributeError: 'str' object has no attribute 'write'
I read that i can use pyuic4 to convert the ui to a py file but doing so every small change need a long work (compiling, etc)
I tried to "save as" with qtCreator but i can't find the PY in the infinite list of available formats
Is there a way to load the UI file in "class definition phase" without converting with pyuic4 every single changes? For me it will be ok to implement a script that compile at the begin with uic.compileUi or something similar
Thanks

I get it with
class MainW(QtGui.QMainWindow):
def __init__(self, *args):
super(MainW, self).__init__(*args)
uic.loadUi("mw.ui", self)
from: http://pyqt.sourceforge.net/Docs/PyQt4/designer.html
PyQt4.uic.loadUi(uifile[, baseinstance=None[, package=”[, resource_suffix=’_rc’]]])
baseinstance – the optional instance of the Qt base class. If
specified then the user interface is created in it. Otherwise a new
instance of the base class is automatically created.

Related

user32.SetWindowCompositionAttribute with PyQt5 causes ctypes.ArgumentError

Recently I installed a python package called BlurWindow via
pip install BlurWindow
This python package helps to achieve a transparent blur background to the application window. Although it says that this module works with tkinter, qt and many other packages, but in my case it only works with tkinter and PySide2 but not with PyQt5.
My code can be seen below:
import sys
from PySide2.QtWidgets import *
from PySide2.QtCore import *
# from PyQt5.QtWidgets import *
# from PyQt5.QtCore import *
from BlurWindow.blurWindow import GlobalBlur
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.setAttribute(Qt.WA_TranslucentBackground)
# self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint | Qt.WindowMinMaxButtonsHint) # set window flags
self.resize(500, 400)
l = QLabel('How do you like the blurry window?', self)
GlobalBlur(self.winId(), Dark=False, Acrylic=False, QWidget=self)
self.setStyleSheet("color: white; background-color: rgba(0, 0, 0, 0)")
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
This code works fine. But when I comment these two lines (line 3 and 4):
from PySide2.QtWidgets import *
from PySide2.QtCore import *
and uncomment these two lines (line 6 and 7):
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
this error occurs:
Traceback (most recent call last):
File "E:\PythonProjects\Zambo\lib\runpy.py", line 197, in _run_module_as_main
return _run_code(code, main_globals, None,
File "E:\PythonProjects\Zambo\lib\runpy.py", line 87, in _run_code
exec(code, run_globals)
File "E:\PythonProjects\Zambo\lib\site-packages\BlurWindow\blurWindow.py", line 191, in <module>
mw = MainWindow()
File "E:\PythonProjects\Zambo\lib\site-packages\BlurWindow\blurWindow.py", line 185, in __init__
GlobalBlur(hWnd,Dark=True,QWidget=self)
File "E:\PythonProjects\Zambo\lib\site-packages\BlurWindow\blurWindow.py", line 160, in GlobalBlur
blur(HWND,hexColor,Acrylic,Dark)
File "E:\PythonProjects\Zambo\lib\site-packages\BlurWindow\blurWindow.py", line 136, in blur
user32.SetWindowCompositionAttribute(HWND, data)
ctypes.ArgumentError: argument 1: <class 'TypeError'>: Don't know how to convert parameter 1
I don't know why this code works with PySide2 but doesn't work with PyQt5!
This is the blurWindow.py module that I'm using in the shown code.
I am on windows 10 and using Python 3.9.5 on an anaconda virtual environment. But I have tested this code on Python 3.6 and 3.8 but the PyQt5 library doesn't work anywhere, instead shows that same error.
I have almost finished my project in which I will implement this blur effect. And since I've used PyQt5 library in my project, replacing PyQt5 library with PySide2 will be a big trouble for me. Any help would be highly appreciated!
At the beginning, I thought it might be the same thing as [SO]: ctypes.ArgumentError when using kivy with pywinauto, but it turns out it's much simpler.
It's a bug in BlurWindow. Running blurWindow.py yields the same behavior (with PyQt5.12.3).
[cfati#CFATI-5510-0:e:\Work\Dev\StackOverflow\q068651351]> sopr.bat
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.08.07_test0\Scripts\python.exe" BlurWindow\blurWindow.py
Traceback (most recent call last):
File "BlurWindow\blurWindow.py", line 188, in <module>
mw = MainWindow()
File "BlurWindow\blurWindow.py", line 182, in __init__
GlobalBlur(hWnd,Dark=True,QWidget=self)
File "BlurWindow\blurWindow.py", line 157, in GlobalBlur
blur(HWND,hexColor,Acrylic,Dark)
File "BlurWindow\blurWindow.py", line 133, in blur
user32.SetWindowCompositionAttribute(HWND, data)
ctypes.ArgumentError: argument 1: <class 'TypeError'>: Don't know how to convert parameter 1
[prompt]> :: Test the 2 modules
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.08.07_test0\Scripts\python.exe" -c "import PyQt5.QtWidgets as pqqw; help(pqqw.QWidget.winId)"
Help on built-in function winId:
winId(...)
winId(self) -> sip.voidptr
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.08.07_test0\Scripts\python.exe" -c "import PySide2.QtWidgets as psqw; help(psqw.QWidget.winId)"
Help on method_descriptor:
winId(self) -> int
winId(self) -> int
As seen, there's a "small" difference between the 2 modules QtWidgets.QWidget.winId's return value. CTypes doesn't know to convert PyQt5's.
Short story
Since you copied the MainWindow code here, the fix is simple, replace:
GlobalBlur(self.winId(), Dark=False, Acrylic=False, QWidget=self)
by:
GlobalBlur(int(self.winId()), Dark=False, Acrylic=False, QWidget=self)
and it should work fine. But check the URL at the next section's beginning to see what you might run into.
Long story
This is more about BlurWindow. The error is when calling (!!!undocumented!!!) user32.SetWindowCompositionAttribute via CTypes. An important point here: [SO]: C function called from Python via ctypes returns incorrect value (#CristiFati's answer). Note that it's Undefined Behavior, and it only works by luck.
Submitted [GitHub]: Peticali/PythonBlurBehind - Fix SetWindowCompositionAttribute failure (merged on 210805). It contains a proper fix to the current issue.
You could download the patch, and apply the changes locally. Check [SO]: Run/Debug a Django application's UnitTests from the mouse right click context menu in PyCharm Community Edition? (#CristiFati's answer) (Patching utrunner section) for how to apply patches on Win (basically, every line that starts with one "+" sign goes in, and every line that starts with one "-" sign goes out). I am using Cygwin, btw. But since it's just one file, you could download it and overwrite your existing one. In any case, back it up first!

Pyqt5, AttributeError: module 'x_ui' has no attribute 'Ui_x'

Hello I have a QTDesigner UI file HelloWorld.ui which I am trying to import into a project and execute.
The Project includes HelloWorld.ui file which has been converted into HelloWorld_ui.py using Pyuic5.
The following is the code of app.py
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
import HelloWorld_ui
class HelloWorld(QDialog, HelloWorld_ui.Ui_HelloWorld):
def __init__(self):
QDialog.__init__(self)
self.setupUi(self)
app = QApplication(sys.argv)
helloworld = HelloWorld()
helloworld.show()
app.exec_()
The following is the error code
Traceback (most recent call last):
File "/Users/rrpolak/Downloads/Pyt/app.py", line 11, in <module>
class HelloWorld(QDialog, HelloWorld_ui.Ui_HelloWorld):
AttributeError: module 'HelloWorld_ui' has no attribute 'Ui_HelloWorld'
Process finished with exit code 1
I am trying to understand what is the correct way to call these files in the python program. Any help is appreciated.
The project file is at https://drive.google.com/open?id=18tjLPiCZxTbKaiZShtgu90KyXcFukr6V
I am using PyQt5/Python3.6/Mac.
If you check the file HelloWorld_ui.py you will notice that there is no class called Ui_HelloWorld, but the class Ui_Dialog:
class Ui_Dialog(object):
so you must use that class:
class HelloWorld(QDialog, HelloWorld_ui.Ui_Dialog):
The name is generated by the name you give to QDialog:
If you want to use HelloWorld you must change it:
convert the .ui to .py again and execute it again obtaining the following:

Pressing button in QFileDialog popup exits application

I made the transition from PyQt4to PyQt5. My app (created with QtDesigner) has a checkbox which enables a "Save" button, in case you want to save your file. In PyQt4 the dialog would open, I'd choose my file, press OK, done. I implemented a check on the OK button of the main application that would prompt an error if the path was invalid, e.g. if you pressed cancel in the QFileDialog.
With PyQt5 my application exits completely if I close the QFileDialog in any way (OK, cancel, X). I want just the QFileDialog to close and not my main window. How do I do this? Thanks for your time and help.
Here's the relevant part of my code:
self.path = self.ui.savepathButton.pressed.connect(lambda: self.file_save())
def file_save(self):
path = QFileDialog.getSaveFileName(self, "Choose a path and filename", os.getcwd().replace("\\", "/") +
"/test.stl", filter="Stereolithography Files (*.stl)")
self.ui.savepath_label.setText(path) <------ NO ERROR WITHOUT THIS LINE
def OKButton_click(self):
if os.path.isdir(os.path.split(self.ui.savepath_label.text())[0]) is False:
# Warning if the filename is invalid.
file_error = QMessageBox()
file_error.setIcon(QMessageBox.Warning)
file_error.setText("Invalid path or filename.")
file_error.setInformativeText("Please choose a working path and filename.") file_error.setWindowTitle("File name error")
file_error.setStandardButtons(QMessageBox.Ok)
file_error.exec_()
else:
self.accept()
Edit:
I know where my error is located, but I still cannot fix it. I marked the line in the code. Why does self.ui.savepath_label.setText(path) terminate my application?
The PyQt4 provides two different APIs:
API v1 uses the Qt types for objects, so you have to pass things like QString to the setText method
API v2 instead uses python types and the methods of the Qt objects automatically convert those python types into their Qt variants, so you have to pass a python str to them.
This is mentioned in this page about PyQt4. PyQt5 only supports version 2 of the API (that page also mentions other differences).
Also note that according to the question pyqt5 - finding documentation the PyQt5 method getSaveFileName actually returns a pair of (filename, filter) so it's effectively equivalent to PyQt4's getSaveFileNameAndFilter method, which means that you could simply use:
self.ui.savepath_label.setText(path[0])
To set the text. Minimal complete example:
from PyQt5.QtWidgets import QFileDialog, QWidget, QApplication, QHBoxLayout, QPushButton
class Window(QWidget):
def __init__(self):
super(Window, self).__init__(None)
layout = QHBoxLayout()
self.button = QPushButton('click')
layout.addWidget(self.button)
self.setLayout(layout)
self.button.clicked.connect(self.ask_filename)
def ask_filename(self):
fname = QFileDialog.getSaveFileName(self, 'title')
print(fname)
self.button.setText(fname[0])
app = QApplication([])
window = Window()
window.show()
app.exec_()
By the way, if you change fname[0] to fname and try to launch this application from the terminal you get the following helpful error message:
Traceback (most recent call last):
File "test_qt.py", line 15, in ask_filename
self.button.setText(fname)
TypeError: QAbstractButton.setText(str): argument 1 has unexpected type 'tuple'
which tells you that the return type of getSaveFileName is a tuple and not a str.
I finally found the (very small) error:
While PyQt4 apparently writes the path automatically as string, PyQt5 does not.
I changed
self.ui.savepath_label.setText(path)
into
self.ui.savepath_label.setText(str(path))
and all is good now.

Trouble using np.genfromtxt in python method

I am writing a python script that uses PyQt and Matplotlib to graph a 2D CSV file. Im still learning python so im having trouble working through some of the errors im getting. One in particular that is troubling me is
Error:
Traceback (most recent call last):
File "C:/Users/jonesza/Documents/Python Scripts/2D-Graph/Qt_2D_Plot.py", line 62, in update_graph
l, v = self.parse_file(self.mpllineEdit.text())
File "C:/Users/jonesza/Documents/Python Scripts/2D-Graph/Qt_2D_Plot.py", line 53, in parse_file
names=['time','temperature'])
File "C:\WinPython\python-2.7.5.amd64\lib\site-packages\numpy\lib\npyio.py", line 1356, in genfromtxt
first_values = split_line(first_line)
File "C:\WinPython\python-2.7.5.amd64\lib\site-packages\numpy\lib_iotools.py", line 208, in _delimited_splitter
line = line.strip(asbytes(" \r\n"))
AttributeError: 'QString' object has no attribute 'strip'
Source code:
# used to parse files more easily
from __future__ import with_statement
# Numpy module
import numpy as np
# for command-line arguments
import sys
# Qt4 bindings for core Qt functionalities (non-Gui)
from PyQt4 import QtCore
# Python Qt4 bindings for GUI objects
from PyQt4 import QtGui
# import the MainWindow widget from the converted .ui files
from qtdesigner import Ui_MplMainWindow
class DesignerMainWindow(QtGui.QMainWindow, Ui_MplMainWindow):
"""Customization for Qt Designer created window"""
def __init__(self, parent = None):
# initialization of the super class
super(DesignerMainWindow, self).__init__(parent)
# setup the GUI --> function generated by pyuic4
self.setupUi(self)
# connect the signals with the slots
QtCore.QObject.connect(self.mplpushButton, QtCore.
SIGNAL("clicked()"), self.update_graph)
QtCore.QObject.connect(self.mplactionOpen, QtCore.
SIGNAL("triggered()"), self.select_file)
QtCore.QObject.connect(self.mplactionQuit, QtCore.
SIGNAL("triggered()"), QtGui.qApp, QtCore.SLOT("quit()"))
def select_file(self):
"""opens a file select dialog"""
# open the dialog and get the selected file
file = QtGui.QFileDialog.getOpenFileName()
# if a file is selected
if file:
# update the lineEdit text with the selected filename
self.mpllineEdit.setText(file)
def parse_file(self, filename):
"""gets first two columns from .csv uploaded"""
#import data from .csv
data = np.genfromtxt(filename, delimiter=',',
names=['time','temperature'])
x = data['time']
y = data['temperature']
return x,y
def update_graph(self):
"""Updates the graph with new letteers frequencies"""
# get the axes for the 2D graph
l, v = self.parse_file(self.mpllineEdit.text())
# clear the Axes
self.mpl.canvas.ax.clear()
# plot the axes
self.mpl.canvas.ax.plot(l,v)
# force an image redraw
self.mpl.canvas.draw()
# create the GUI application
app = QtGui.QApplication(sys.argv)
# instantiate the main window
dmw = DesignerMainWindow()
# show it
dmw.show()
# start the Qt main loop execution, exiting from this script
# with the same return code of Qt application
sys.exit(app.exec_())
Thanks ahead of time for any help.
I assume self.mpllineEdit.text() produces a QString. You need to explore, either in PyQt documentation, or an interactive shell, what methods it has, and if you need need to do anything to convert it to a regular Python string. genfromtxt is attempting to split that string into lines, and then strip off the line ending characters, so it can then parse the line.
Try:
self.parse_file(str(self.mpllineEdit.text()))
That might convert the Qstring to a regular Python string.

Difficulty accessing widgets after loading interface from ui file with loadUi()

I like the idea of using the loadUi() method in PyQt to load in a QtDesigner interface file as I'm often changing the ui file and don't want to be constantly converting it to a py file.
However, I've been having difficulty understanding how to access the different widgets and views in my ui file. The below shows how I'm loading in the ui:
class MyClass(QtGui.QMainWindow):
def __init__(self, parent = None):
super().__init__(parent)
ui = uic.loadUi('MyUserInterface.ui',self)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
mainapplication = MyClass()
mainapplication.show()
app.exec_()
It displays fine, but I was expecting that I would be able to access the elements of the GUI by something along the lines of...
ui.sampleButton.makeDraggable()
My question is, how can I access the various elements within my GUI?
Edit 1: I Also have tried to without assigning the uic.load call to ui. When accessing as shown below, I can access some of the properties through using Ui_MainWindow. However, it throws an error
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
mainapplication = MyClass()
mainapplication.Ui_MainWindow.graphicsView.acceptDrops(True)
mainapplication.show()
app.exec_()
The error i get is...
Traceback (most recent call last): File "C:\Users\Me\workspaces\com.samplesoftware.software\src\SoftwareView\MyClass.py", line 17, in <module>
mainapplication.Ui_MainWindow.graphicsView.acceptDrops(True)
AttributeError: 'MyClass' object has no attribute 'Ui_MainWindow'
Any ideas?
You don't need to convert it to a .py file but you definitely have to name them to access them, otherwise you need to know what the sampleButton is called in the ui file.
you can simply rename the sampleButton to my_btn and access it..
The loadUi function takes a ui file path as the first argument, and a base-instance as the second argument.
The base-instance should be the same Qt class as the top-level widget in the UI. This is because loadUi will insert all the UI into the base-instance, and may need to call some of its methods in doing so. All the child widgets that are defined in the UI will end up as attributes of the base-instance.
So you should call loadUi like this in your __init__:
class MyClass(QtGui.QMainWindow):
def __init__(self, parent = None):
super(MyClass, self).__init__(parent)
uic.loadUi('MyUserInterface.ui', self)
And you should then be able to access graphicsView like this:
self.graphicsView.setAcceptDrops(True)
I found out the reason why was because I was trying to call the Ui_MainWindow prior to running app.exec_(). After moving the Ui_MainWindow call to the end it does work. I'm guessing, and it does make sense in hindsight, the MainWindow needs to exist before its properties can be altered.

Categories

Resources