I'm trying to save an image to the system clipboard, so I wrote some code like this:
#!/usr/bin/python3
from PyQt5.Qt import QApplication
from PyQt5.QtWidgets import QWidget, QPushButton
from PyQt5.Qt import QImage
import sys
class MyWidget(QWidget):
def __init__(self):
super(MyWidget, self).__init__()
self.button = QPushButton(self)
self.button.clicked.connect(self.copyPicToClip)
def copyPicToClip(self):
image = QImage('./test.jpg')
QApplication.clipboard().setImage(image)
self.close()
if __name__ == '__main__':
a = QApplication(sys.argv)
myW = MyWidget()
myW.show()
a.exec()
Sadly, I found it doesn't work at all. Then I tried to find a solution. The first thing I tried was this:
def copyPicToClip(self):
image = QImage('./test.jpg')
QApplication.clipboard().setImage(image)
# self.close()
After this, I just found that it worked, but the window does not close automatically.
Then I tried with copying text:
#!/usr/bin/python3
from PyQt5.Qt import QApplication, QClipboard
from PyQt5.QtWidgets import QWidget, QPushButton
from PyQt5.Qt import QImage
import sys
class MyWidget(QWidget):
def __init__(self):
super(MyWidget, self).__init__()
self.button = QPushButton(self)
self.button.clicked.connect(self.copyPicToClip)
QApplication.clipboard().dataChanged.connect(self.testFunc)
def copyPicToClip(self):
image = QImage('./test.jpg')
QApplication.clipboard().setImage(image)
def testFunc(self):
print('Here')
self.close()
if __name__ == '__main__':
a = QApplication(sys.argv)
myW = MyWidget()
myW.show()
a.exec()
Sadly, it failed again.
So, it seems that if I close the application to early, the image won't be saved to the clipboard. But I want to close it after copying the image to the clipboard.
Any suggestions?
(PyQt5, ubuntu 16.10, if helps).
Unfortunately for you, this is "normal" behaviour on Linux. By default, clipboard data is not persisted when an application closes. The usual work-around for this problem is to install a clipboard manager. For Ubuntu, see this wiki article for more details:
Ubuntu Wiki: Clipboard Persistence
(NB: I have not actually tested any of the suggested solutions myself, so I don't know whether any of them will work with PyQt).
The basic problem is that on Linux, the clipboard only stores a reference to the underlying data. This is very efficient in terms of storage, because the data is only copied when the client program actually requests it. But of course if the source application closes, the reference will be invalidated, and the clipboard will become empty.
Related
I have a fresh QtCreator installation, and I set it up to run using a fresh install of Python3.8 on which I pip-installed both pyside2 and pyside6.
When I create a new Qt for Python - Window (UI file) application, whatever I do to the UI file the window always shows up empty and with the default size when I run the app.
I've tried with a QDialog, QMainApplication, using Pyside2 or Pyside6, I've checked that it was correctly loading the UI (and the right one) - no dice. It just won't update, and appears not to have any reason not to.
Default code for completeness:
# This Python file uses the following encoding: utf-8
import os
from pathlib import Path
import sys
from PySide2.QtWidgets import QApplication, QDialog
from PySide2.QtCore import QFile
from PySide2.QtUiTools import QUiLoader
class Dialog(QDialog):
def __init__(self):
super(Dialog, self).__init__()
self.load_ui()
def load_ui(self):
loader = QUiLoader()
path = os.fspath(Path(__file__).resolve().parent / "form.ui")
ui_file = QFile(path)
ui_file.open(QFile.ReadOnly)
loader.load(ui_file, self)
ui_file.close()
if __name__ == "__main__":
app = QApplication([])
widget = Dialog()
widget.show()
sys.exit(app.exec_())
(In the UI I just drag-dropped a button right in the middle and saved the file)
Am I forgetting something fundamental? I'm only used to programming in C++ using QtCreator.
I was expecting this to work right out of the box, but it's not.
This only dynamically load the UI as a new widget, with this custom class as a parent.
If I want signals and slots to work, the only thing I've found was to add a custom build step:
Command: <path to pyside6 install, use pip show to know where>\uic.exe
Arguments: <filename of the .ui file> -o <the python translation .py
which will serve as baseclass> -g python
Working directory: [your project dir]
Then signals and slots need to be connected manually, so QtCreator really only enables you to draw the user interface but all the logic still needs to be done by hand. Component variables are normally named after their UI name, but you can see for yourself in the baseclass file. This is a big step back from how QtCreator is used in C++ ("go to slot" will not work).
Code to use:
import sys
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtCore import QFile
from PySide6.QtUiTools import QUiLoader
from YourGenPyFileName import Ui_YourUIName
class MainWindow(QMainWindow, Ui_YourUIName):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
if __name__ == "__main__":
app = QApplication([])
widget = MainWindow()
widget.show()
sys.exit(app.exec_())
I try to read dataframe from excel file and print it after button click.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QMessageBox
from PyQt5.QtGui import QIcon
from excel_reading import *
class MyWin(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.hello)
def hello(self):
data_input_from_file = QtWidgets.QFileDialog.getOpenFileName(self,'header','filename','Excel (*.xlsx *.xls)')
print(data_input_from_file)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
myapp = MyWin()
myapp.show()
sys.exit(app.exec_())
When I click button, I have such message:
Gtk-Message: 00:03:53.573: GtkDialog mapped without a transient parent. This is discouraged.
('', '')
How should I solve that problem?
I solved the problem:
def hello(self):
data_input_from_file = QtWidgets.QFileDialog.getOpenFileName(self, 'header', 'filename', 'Excel (*.xlsx *.xls)')
print(type(data_input_from_file))
print(data_input_from_file)
print(pd.read_excel(data_input_from_file[0]))
The Gtk warning is just what it is: a warning. You can ignore that. Qt tries to use the system native file dialogs whenever possible, which might result in some warnings in the consolle output.
Your issue is related to something else: there are rare cases for which PyQt functions don't return the same signature as reported in the official Qt (C++) documentation.
QFileDialog static methods is one of such cases, as QFileDialog.getOpenFileName() always returns a tuple: the selected file path and the selected file type filter. This is also clear from the output of your code (which I suppose is caused by cancelling the dialog):
('', '')
The first value is the selected file (in this case, none) and filter (again, none, as there was no selected file).
The solution is to assign two values for what the static returns:
filePath, filters = QtWidgets.QFileDialog.getOpenFileName(
self,'header','filename','Excel (*.xlsx *.xls)')
if filePath:
# do something
I created a UI in designer, converted it to python using pyside-uic and then following a tutorial I did this:
from PySide import QtCore, QtGui
import mirroratorUI as customUI
#import mirroratorCore as mirroratorCore
from shiboken import wrapInstance
import maya.OpenMayaUI as omui
reload(customUI)
def maya_main_window():
main_window_ptr = omui.MQtUtil.mainWindow()
return wrapInstance(long(main_window_ptr), QtGui.QWidget)
class ControlMainWindow(QtGui.QDialog):
def __init__(self, parent=None):
super(ControlMainWindow, self).__init__(parent)
self.setWindowFlags(QtCore.Qt.Tool)
self.ui = customUI.Ui_MainWindow()
self.ui.setupUi(self)
myWin = ControlMainWindow(parent=maya_main_window())
myWin.show()
The UI will be used into Maya, and it appears, but if I open it 3 times, I will have 3 dialgos. I remember there is a way to check if the dialog already exists, and if it does, deleting it. I found some info on google but I either didn't understand how to sue those info or they were not fit to my case...
Many thanks for your help,
Daniele
Please try the below code.
global myWin
try:
myWin.close()
except:
pass
myWin = ControlMainWindow(parent=maya_main_window())
myWin.show()
The above code just finds out whether the windows exists and if it exists it will close and creates the window as usual.
I am using PyQt5 5.5.1 (64-bit) with Python 3.4.0 (64-bit) on Windows 8.1
64-bit.
I am having trouble restoring the position and size (geometry) of my
very simple PyQt app.
Here is minimal working application:
import sys
from PyQt5.QtWidgets import QApplication, QWidget
class myApp(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
view = myApp()
sys.exit(app.exec())
What I read online is that this is the default behavior and we need to
use QSettings to save and retrieve settings from Windows registry,
which is stored in
\\HKEY_CURRENT_USER\Software\{CompanyName}\{AppName}\
Here are some of the links I read.
I could have followed those tutorials but those tutorials/docs were
written for C++ users.
C++ is not my glass of beer, and converting those codes are impossible to me.
Related:
QSettings(): How to save to current working directory
This should do.
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import QSettings, QPoint, QSize
class myApp(QWidget):
def __init__(self):
super(myApp, self).__init__()
self.settings = QSettings( 'My company', 'myApp')
# Initial window size/pos last saved. Use default values for first time
self.resize(self.settings.value("size", QSize(270, 225)))
self.move(self.settings.value("pos", QPoint(50, 50)))
def closeEvent(self, e):
# Write window size and position to config file
self.settings.setValue("size", self.size())
self.settings.setValue("pos", self.pos())
e.accept()
if __name__ == '__main__':
app = QApplication(sys.argv)
frame = myApp()
frame.show()
app.exec_()
I simplified this example: QSettings(): How to save to current working directory
Similar to #Valentin's response, because I feel settings are being written to registry, which will be issue for cross compatiblity. Here is the relevant startEvent() and closeEvent() for the job.
def startEvent()
self.settings = QSettings(QSettings.IniFormat,QSettings.SystemScope, '__MyBiz', '__settings')
self.settings.setFallbacksEnabled(False) # File only, not registry or or.
# setPath() to try to save to current working directory
self.settings.setPath(QSettings.IniFormat,QSettings.SystemScope, './__settings.ini')
# Initial window size/pos last saved
self.resize(self.settings.value("size", QSize(270, 225)))
self.move(self.settings.value("pos", QPoint(50, 50)))
self.tab = QWidget()
def closeEvent(self, e):
# Write window size and position to config file
self.settings.setValue("size", self.size())
self.settings.setValue("pos", self.pos())
startEvent() should be initiated at startup and closeEvent() should be taken care before quitting the main window.
You should indeed use QSetting for this.
All the Qt examples have been converted to Python. They are included in the source packages of PyQt (or PySide), which you can download here
You can also look online in the github repo, particularly in application.py of mainwindows example.
def readSettings(self):
settings = QSettings("Trolltech", "Application Example")
pos = settings.value("pos", QPoint(200, 200))
size = settings.value("size", QSize(400, 400))
self.resize(size)
self.move(pos)
def writeSettings(self):
settings = QSettings("Trolltech", "Application Example")
settings.setValue("pos", self.pos())
settings.setValue("size", self.size())
Fire writeSettings() before quitting and initiate readSettings() on startup.
In my case I use .ini files to store settings (language, default user, ...). the same code works on both Debian and Windows.
An example:
from PySide.QtCore import QSettings
self.settings = QSettings('settings.ini', QSettings.IniFormat)
...
self.settings.setValue('size', self.size())
I am looking for a simple example of how to directly load a QtDesigner generated .ui file into a Python application.
I simply would like to avoid using pyuic4.
For the complete noobs at PySide and .ui files, here is a complete example:
from PySide import QtCore, QtGui, QtUiTools
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
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
MainWindow = loadUiWidget(":/forms/myform.ui")
MainWindow.show()
sys.exit(app.exec_())
PySide, unlike PyQt, has implemented the QUiLoader class to directly read in .ui files.
From the linked documentation,
loader = QUiLoader()
file = QFile(":/forms/myform.ui")
file.open(QFile.ReadOnly)
myWidget = loader.load(file, self)
file.close()
Another variant, based on a shorter load directive, found on https://askubuntu.com/questions/140740/should-i-use-pyqt-or-pyside-for-a-new-qt-project#comment248297_141641. (Basically, you can avoid all that file opening and closing.)
import sys
from PySide import QtUiTools
from PySide.QtGui import *
app = QApplication(sys.argv)
window = QtUiTools.QUiLoader().load("filename.ui")
window.show()
sys.exit(app.exec_())
Notes:
filename.ui should be in the same folder as your .py file.
You may want to use if __name__ == "__main__": as outlined in BarryPye's answer
Here is some example for PySide6 and Windows. (For linux you need use /, not \\)
from PySide6.QtUiTools import QUiLoader
from PySide6.QtCore import QFile
from PySide6.QtWidgets import QApplication
import sys
if __name__ == "__main__":
app = QApplication(sys.argv)
loader = QUiLoader()
file = QFile("gui.ui")
file.open(QFile.ReadOnly)
ui = loader.load(file)
file.close()
ui.show()
sys.exit(app.exec_())
For people coming from PyQt5/6 who are thoroughly confused by this:
PySide does not have the same functionality that we're used to, which is to load the ui file at the top of the window/widget subclass like so:
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
'''Load ui'''
uic.loadUi("mainwindow.ui", self)
There is nothing very similar to this in PySide.
Instead, the best thing to do is embrace the ui-file compilation that you've avoided because loading the ui file is so easy in PyQt. This has a couple of advantages
There is a performance advantage - the ui file does not need to be compiled at run time
You get type hints for all your widgets without needing to manually add them
The disadvantage is that you have to use pyside6-uic to compile the *.ui files each time you edit them, but this can be made less painful by using scripts to automate the process - either setting it up in VSCode, a batch file or a powershell script. After you've done this, the code is nice:
#ui_mainwindow is the ui_mainwindow.py file
#Ui_MainWindow is the class that was produced within that .py file
from ui_mainwindow import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow, self).__init__()
'''Load the ui'''
self.setupUi(self)