is it possible to set the translataable checkbox for everything inside the qtdesigner to disabled as default. I only need one language and much prefer the cleaner auto generated code, leaving the retranslateUI funtion empty and setting everything up in the constructor.
Setting the checkbox for everything to disabled is super annoying.
Qt designer does not allow to do it, that is the default configuration that plugins have, so I will propose a workaround, modify the .ui with a small script to disable that property:
from PyQt4 import QtCore, QtXml
if __name__ == '__main__':
filename = "/path/of/your_file.ui"
file = QtCore.QFile(filename)
if not file.open(QtCore.QFile.ReadOnly):
sys.exit(-1)
doc = QtXml.QDomDocument()
if not doc.setContent(file):
sys.exit(-1)
file.close()
strings = doc.elementsByTagName("string")
for i in range(strings.count()):
strings.item(i).toElement().setAttribute("notr", "true")
if not file.open(QtCore.QFile.Truncate|QtCore.QFile.WriteOnly):
sys.exit(-1)
xml = doc.toByteArray()
file.write(xml)
file.close()
Note:
The script is compatible with PyQt4, PyQt5, PySide and PySide2, they should only change PyQt4 with the name of the other libraries.
Related
I am using PyQt5 QFileDialog.getOpenFileName. I am expecting the box to remain open until the "open" button is clicked. However, when I run the code on my Linux system, the dialog box closes immediately when the file name is clicked. On a Windows system, the box behaves as expected and remains open until the 'Open' button is clicked. The results are the same with or without the QFileDialog.DontUseNativeDialog option set.
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QFileDialog
import sys
class Main(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("QFileDialog Test")
button = QPushButton("Click to open file")
button.setCheckable(True)
button.clicked.connect(self.open_file)
# Set the central widget of the Window.
self.setCentralWidget(button)
def open_file(self):
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
file_name, _ = QFileDialog.getOpenFileName(None, "Open File",
"", "Python Files (*.py);;Text Files (*.txt)",options=options)
app = QApplication(sys.argv)
window = Main()
window.show()
app.exec_()
Edit:
I logged out of KDE and started an Openbox session instead, then ran the above code. QFileDialog behaved as I was expecting, and waited for me to click the Open button. This verifies the problem exists with KDE / KWin, and that the code, run under other window managers, will likely work fine.
Still isn't a real solution, but I am more informed now than I was earlier.
2nd Edit:
I found that if I change Workspace Behavior -> General Behavior -> Click Behavior from Single click, to Double click, my QFileDialog issue goes away. How to get around this would be a different topic though.
3rd Edit:
Added 'QFileDialog.DontUseNativeDialog' option to sample code.
It seems like Qt tries to respect the way the OS opens files and folders in its file manager, even when using the native dialog. That depends on the SH_ItemView_ActivateItemOnSingleClick style hint, and the only way to bypass it is to apply a proxy style.
While you could apply the style to the QFileDialog's view within its __init__ (as long as you're using the native dialog), you're using static methods, so you can only do this by setting the style to the whole QApplication.
Note that, unlike stylesheets, palette and font, styles are not propagated to children widgets, and they always use the QApplication style (or the style manually set for them).
class SingleClickWorkaroundProxy(QProxyStyle):
def styleHint(self, hint, option, widget, data):
if hint == self.SH_ItemView_ActivateItemOnSingleClick:
return False
return super().styleHint(hint, option, widget, data)
# ...
app = QApplication(sys.argv)
app.setStyle(SingleClickWorkaroundProxy())
window = Main()
window.show()
app.exec_()
I need to add some features to a graphics widget in a form I created using the Qt Designer.
For example I would normally do something like this:
class custom_gv(QGraphicsView):
def __init__(self):
super().__init__()
def zoom(self):
# custom code here
But in this case the graphics view is a part of the window I made in Qt Designer. I know you can use the "promote to" feature in Qt designer but I don't know how to utilise that in code, especially considering that I use this method to use Qt Designer windows:
from PyQt5.uic import loadUiType
custom_window = loadUiType('ui.ui')
class Window(QMainWindow, custom_window):
def __init__(self):
QMainWindow.__init__(self)
custom_window.__init__(self)
self.setupUi(self)
So how would I go about customising the code of the graphics view in my window when I use Qt Designer?
The most common way to solve this is by using widget promotion. This will allow you to replace a widget defined in Qt Designer with your own custom class. The steps for doing this are as follows:
In Qt Designer, select the QGraphicsView you want to replace, then right-click it and select Promote to... . In the dialog, set Promoted class name to "custom_gv", and set Header file to the python import path for the module that contains this class (e.g. "mypkg.widgets"). Then click Add, and Promote, and you will see the class change from "QGraphicsView" to "custom_gv" in the Object Inspector pane.
When the Qt Designer ui file is converted into PyQt code, it will automatically add an import statement like this:
from mypkg.widgets import custom_gv
and then in the converted code it will replace something like this:
self.graphicsView = QtWidgets.QGraphicsView(MainWindow)
with this:
self.graphicsView = custom_gv(MainWindow)
So the code in the ui file knows nothing about the custom class: it's just a name that is imported from elsewhere. That means you are completely free to write the custom class in any way you like.
In PyQt, this mechanism works in the same way with pyuic as it does with the uic module. The loadUi and loadUiType functions generate exactly the same code as pyuic does. The only difference is that the pyuic tool writes the generated code to a file, whereas the uic module loads it directly via exec.
This question already has answers here:
QtDesigner changes will be lost after redesign User Interface
(2 answers)
Closed 4 years ago.
I've been looking for a better way to work with frontends made using qtDesigner connected to a python backend. All the methods I have found have the following form:
Make GUI in designer
Output to python code using pyuic (usually with -x option)
Write backend code inside this output file
This methodology is not simple to maintain or edit. Any time you change the UI, it completely breaks workflow: you have to reconvert, generate a new file, fix that file back up to where you were before, then finally get back on track. This requires a lot of manual copy-paste of code, which is an invitation to errors on multiple levels (newly generated file layout may not be the same, manually fixing name changes while pasting, etc.). You can also end up losing work if you aren't careful, since you could accidentally overwrite the file and destroy the backend code.
Also, this doesn't use any of the control in qtDesigner like the Signal/Slot and Action editors. These must be here for something, but I can't find a way to actually direct these to call backend functions.
Is there a better way to work with this, possibly using the features of qtDesigner?
You don't have to add your code in the output file :
If you take a 'home.py' generated by PYUIC, containing a QMainWindow which name set by QtDesigner/generated by Puic would be Ui_Home(), your main code could be :
from home import Ui_Home
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class window_home(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
#set up the user interface from Designer
self.ui = Ui_Home()
self.ui.setupUi(parent)
#then do anything as if you were in your output file, for example setting an image for a QLabel named "label" (using QtDesigner) at the root QMainWindow :
self.ui.label.setPixmap(QPixmap("./pictures/log.png"))
def Home():
f=QMainWindow()
c=window_home(f)
f.show()
r=qApp.exec_()
if __name__=="__main__":
qApp=QApplication(sys.argv)
Home()
I found an even cleaner method for working with this, that does not require preemptive conversion after each edit at all. Instead it takes the .ui file itself, so all you need to do is restart the program itself to update the design.
import sys
import os
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5 import uic
path = os.path.dirname(__file__) #uic paths from itself, not the active dir, so path needed
qtCreatorFile = "XXXXX.ui" #Ui file name, from QtDesigner, assumes in same folder as this .py
Ui_MainWindow, QtBaseClass = uic.loadUiType(path + qtCreatorFile) #process through pyuic
class MyApp(QMainWindow, Ui_MainWindow): #gui class
def __init__(self):
#The following sets up the gui via Qt
super(MyApp, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
#set up callbacks
self.ui.NAME OF CONTROL.ACTION.connect(self.test)
def test(self):
#Callback Function
if __name__ == "__main__":
app = QApplication(sys.argv) #instantiate a QtGui (holder for the app)
window = MyApp()
window.show()
sys.exit(app.exec_())
Note that this is Qt5. Qt5 and Qt4 are not API compatible, so it will be a little different in Qt4 (and presumably earlier as well).
I need to add some features to a graphics widget in a form I created using the Qt Designer.
For example I would normally do something like this:
class custom_gv(QGraphicsView):
def __init__(self):
super().__init__()
def zoom(self):
# custom code here
But in this case the graphics view is a part of the window I made in Qt Designer. I know you can use the "promote to" feature in Qt designer but I don't know how to utilise that in code, especially considering that I use this method to use Qt Designer windows:
from PyQt5.uic import loadUiType
custom_window = loadUiType('ui.ui')
class Window(QMainWindow, custom_window):
def __init__(self):
QMainWindow.__init__(self)
custom_window.__init__(self)
self.setupUi(self)
So how would I go about customising the code of the graphics view in my window when I use Qt Designer?
The most common way to solve this is by using widget promotion. This will allow you to replace a widget defined in Qt Designer with your own custom class. The steps for doing this are as follows:
In Qt Designer, select the QGraphicsView you want to replace, then right-click it and select Promote to... . In the dialog, set Promoted class name to "custom_gv", and set Header file to the python import path for the module that contains this class (e.g. "mypkg.widgets"). Then click Add, and Promote, and you will see the class change from "QGraphicsView" to "custom_gv" in the Object Inspector pane.
When the Qt Designer ui file is converted into PyQt code, it will automatically add an import statement like this:
from mypkg.widgets import custom_gv
and then in the converted code it will replace something like this:
self.graphicsView = QtWidgets.QGraphicsView(MainWindow)
with this:
self.graphicsView = custom_gv(MainWindow)
So the code in the ui file knows nothing about the custom class: it's just a name that is imported from elsewhere. That means you are completely free to write the custom class in any way you like.
In PyQt, this mechanism works in the same way with pyuic as it does with the uic module. The loadUi and loadUiType functions generate exactly the same code as pyuic does. The only difference is that the pyuic tool writes the generated code to a file, whereas the uic module loads it directly via exec.
I wrote a lot of custom widget plug-ins for using them in the Qt Designer and my Pipeline.
This is working fine on my Mac (Mavericks, PyQt4, Python 2.7), and this week I wanted to implement those plugins on my Windows environment as well. But it wasn't working. The plug-ins are not appear in the Qt Designer's Widget Box on the left (Windows 7, PyQt4, Python 2.7).
After a lot of try's, I downloaded the PyQt4 example files and followed the instructions from: PyQt Reference Guide and also the instructions
from the example launcher file examples/designer/plugins/plugins.py itself, but it was still not working.
So I copied the the following example files:
plugin files to "C:\designer_plugins"
widget files to "C:\designer_widgets"
Just to making the code as simple as possible to figure out what is going wrong.
So, this is my testing plugins.py file:
#!/usr/bin/env python
import sys
import os
from PyQt4 import QtCore, QtGui, uic
env = os.environ.copy()
env['PYTHONPATH'] = r"C:\designer_widgets" #("%s"%os.pathsep).join(sys.path)
env['PYQTDESIGNERPATH'] = r"C:\designer_plugins"
qenv = ['%s="%s"' % (name, value) for name, value in env.items()]
# Start Designer.
designer = QtCore.QProcess()
designer.setEnvironment(qenv)
designer_bin = r"C:\Python27x64\Lib\site-packages\PyQt4\designer.exe"
designer.start(designer_bin)
designer.waitForFinished(-1)
sys.exit(designer.exitCode())
I thought that my designer object didn't get the right path, so I implemented the folowing to check it's environment:
# Check if paths are right
print "\n # Designer Env:"
for pypath in designer.environment():
if "PYTHONPATH" in pypath:
print " # ",pypath
if "PYQTDESIGNERPATH" in pypath:
print " # ",pypath
Console output:
# Designer Env:
# PYQTDESIGNERPATH="C:\designer_plug"
# PYTHONPATH="C:\designer_widgets"
The paths are right. And like I said, on my mac it works perfectly.
I was trying this also with different Qt Designer installations. But both (PyQt4 and PySide) designers doesn't show any of the example plugins. Both Qt Designer couldn't find the example plugins. I double checked it inside the designer with Help/About Plugins).
Any ideas what I did wrong? Or is this generally not working on a Windows 7 System?
All fixed. I rebuild PyQt4, so I think I made probably a mistake in the source code of Qt in the past.