PySide2 display same icon in file dialog as main window - python

I have a simple pyside2 application which looks kinda like this:
import sys
from PySide2.QtWidgets import QApplication, QDialog, QPushButton, QFileDialog, QVBoxLayout
from PySide2 import QtGui
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.setWindowTitle("My Form")
self.setWindowIcon(QtGui.QIcon("myicon.png"))
layout = QVBoxLayout()
self.button = QPushButton("Open dialog")
self.button.clicked.connect(self.browse)
layout.addWidget(self.button)
self.setLayout(layout)
def browse(self):
qfd = QFileDialog()
qfd.setWindowIcon(QtGui.QIcon("myicon.png"))
filename, _ = qfd.getOpenFileName(None, "Load Data", ".", "*.txt")
if __name__ == '__main__':
# Create the Qt Application
app = QApplication(sys.argv)
# Create and show the form
form = Form()
form.show()
# Run the main Qt loop
sys.exit(app.exec_())
I want to setup the same icon for the QFileDialog as the main window icon but for some reason it does not work. Is there a way to set it like I'm trying above? Thanks for ideas, pointers and help in advance! (I'm using Ubuntu 20.04)

The getOpenFileName method is a static method that creates an internal QFileDialog other than "qfd" so the icon is not applied. One possible option is not to use getOpenFileName but to create the logic only using the QFileDialog class, and another solution is to access the QFileDialog object created inside getOpenFileName using the characteristic that is a toplevel:
import sys
from PySide2 import QtCore, QtGui, QtWidgets
class Form(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.setWindowTitle("My Form")
self.setWindowIcon(QtGui.QIcon("myicon.png"))
layout = QtWidgets.QVBoxLayout(self)
self.button = QtWidgets.QPushButton("Open dialog")
self.button.clicked.connect(self.browse)
layout.addWidget(self.button)
def browse(self):
QtCore.QTimer.singleShot(0, self.handle_timeout)
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
None,
"Load Data",
".",
"*.txt",
options=QtWidgets.QFileDialog.DontUseNativeDialog,
)
def handle_timeout(self):
for w in QtWidgets.QApplication.topLevelWidgets():
if isinstance(w, QtWidgets.QFileDialog):
w.setWindowIcon(QtGui.QIcon("myicon.png"))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
form = Form()
form.show()
sys.exit(app.exec_())

Related

Why does the QMainWindow not show? [duplicate]

I am loading a QMainWindow from an .ui file - it's working fine but window events like resize won't be triggered. I can't really figure out what I am doing wrong.
This is the code:
class TestWindow(QMainWindow):
def __init__(self, parent=None):
super(TestWindow, self).__init__(parent)
loader = QUiLoader()
file = QFile(abspath("ui/mainwindow.ui"))
file.open(QFile.ReadOnly)
self.window = loader.load(file, parent)
file.close()
self.window.show()
def resizeEvent(self, event):
print "resize"
app = QApplication(sys.argv)
test = TestWindow()
sys.exit(app.exec_())
The .ui file can be found here.
It seems that you have a confusion, but for you to understand call the test method of TestWindow:
import os
from PySide2 import QtCore, QtWidgets, QtUiTools
class TestWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(TestWindow, self).__init__(parent)
loader = QtUiTools.QUiLoader()
file = QtCore.QFile(os.path.abspath("ui/mainwindow.ui"))
file.open(QtCore.QFile.ReadOnly)
self.window = loader.load(file, parent)
file.close()
self.window.show()
self.show()
def resizeEvent(self, event):
print("resize")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
test = TestWindow()
sys.exit(app.exec_())
And if you move the small window observe that the event is triggered.
Why does that happen?: QUiLoader creates a widget based on the .ui that unlike uic.loadUi() or ui.loadUiType() of PyQt5 does not load in the main widget but creates a new widget, maybe that's a disadvantage but that's the limitations.
So depending on what you want to do there are several options:
To load the .ui with QUiLoader() it is not necessary to have TestWindow as a parent since it can be a QObject that monitors the events through an event filter.
import os
from PySide2 import QtCore, QtWidgets, QtUiTools
class Manager(QtCore.QObject):
def __init__(self, parent_widget=None, parent=None):
super(Manager, self).__init__(parent)
loader = QtUiTools.QUiLoader()
file = QtCore.QFile(os.path.abspath("ui/mainwindow.ui"))
file.open(QtCore.QFile.ReadOnly)
self.window = loader.load(file, parent_widget)
file.close()
self.window.installEventFilter(self)
self.window.show()
self.setParent(self.window)
self.window.destroyed.connect(lambda *args: print(">>>>>>"))
def eventFilter(self, obj, event):
if event.type() == QtCore.QEvent.Close and self.window is obj:
self.window.removeEventFilter(self)
elif event.type() == QtCore.QEvent.Resize and self.window is obj:
print("resize")
return super(Manager, self).eventFilter(obj, event)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
test = Manager()
sys.exit(app.exec_())
Another option is to make the self.widow the centralwidget (the QMainWindow in the .ui will be the centralwidget of the TestWindow, so the resize will be from the TestWindow not from the .ui but as if the size of the .ui is changed, the same will happen with TestWindow):
import os
from PySide2 import QtCore, QtWidgets, QtUiTools
class TestWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(TestWindow, self).__init__(parent)
loader = QtUiTools.QUiLoader()
file = QtCore.QFile(os.path.abspath("ui/mainwindow.ui"))
if file.open(QtCore.QFile.ReadOnly):
self.window = loader.load(file, parent)
file.close()
self.setCentralWidget(self.window)
self.show()
def resizeEvent(self, event):
print("resize")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
test = TestWindow()
sys.exit(app.exec_())
The previous methods only serve to notify you of the event but if you want to overwrite it is better that you use pyuic converting the .ui to .py

QToolBar does not show text next to icon

I have the following code:
from PyQt5 import QtWidgets
from PyQt5.QtGui import QIcon
class ConfigureBar(QtWidgets.QToolBar):
def __init__(self, parent=None):
super().__init__(parent)
self.addAction(QtWidgets.QIcon("some_icon.png"), "Hi")
self.addSeparator()
self.addAction(QIcon("some_icon.png"), "Hello")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = ConfigureBar()
window.show()
app.exec()
But for some reason, the displayed widget does not have a text (Hi, Hello), only the icon. I tried to find some answer but I can't seem to get the keyword right. Help?
The toolButtonStyle property indicates the style of how the QToolButtons are shown, and by default it is Qt::ToolButtonIconOnly, so only show the icon, if you want to show the text you have to use Qt::ToolButtonTextBesideIcon or Qt::ToolButtonTextUnderIcon:
from PyQt5 import QtCore, QtGui, QtWidgets
class ConfigureBar(QtWidgets.QToolBar):
def __init__(self, parent=None):
super().__init__(parent)
self.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
# or
# self.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)
self.addAction(QtGui.QIcon("some_icon.png"), "Hi")
self.addSeparator()
self.addAction(QtGui.QIcon("some_icon.png"), "Hello")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
toolbar = ConfigureBar()
w = QtWidgets.QMainWindow()
w.addToolBar(toolbar)
w.show()
sys.exit(app.exec_())

how to confine a xterm/rcvt/gnome-terminal to a specific region of screen

I want to launch a QProcess and have it display / render in a specific region of the screen. The process is an xterm(1) or rcvt(1) or gnome-terminal(1) and I embed the rxvt(1) onto my main window.
self.winIdStr = str(int(self.winId()))
self.process.start('rxvt', ['-embed', self.winIdStr , '-e', './goo'])
But my main window looks like this:
And I want to confine rxvt(1) to the QTextEdit area. Unfortunately I don't know Qt lingo well. So would I need to create a QFrame or some other thing to get this going?
You have to create a QWidget where you want the terminal to be placed and pass the winId() of that widget:
from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.container = QtWidgets.QWidget()
self.container.setFixedSize(600, 400)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(QtWidgets.QLineEdit())
lay.addWidget(QtWidgets.QPushButton())
lay.addWidget(self.container)
self.process = QtCore.QProcess(self)
self.winIdStr = str(int(self.container.winId()))
self.process.start("rxvt", ["-embed", self.winIdStr, "-e", "./goo"])
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())

Pyside2 second window(QDialog) closes the main one

import sys
from PySide2.QtCore import QFile
from PySide2.QtWidgets import QApplication, QMainWindow
from PySide2.QtUiTools import QUiLoader
class MyMainWindow(QMainWindow):
def __init__(self):
super().__init__()
loader = QUiLoader()
self.ui = loader.load("mainWindow.ui", self)
self.ui.pushButton_call_dialog.clicked.connect(self.call_dialog)
self.ui.close()
self.ui.show()
def call_dialog(self):
loader = QUiLoader()
self.dialog = loader.load("dialog.ui")
self.dialog.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyMainWindow()
window.show
sys.exit(app.exec_())
Hi everyone,
any idea why the second (dialog) window closes the entire application?
Of course, it is not a crash since i'm getting a message saying:
Process finished with exit code 0
Thanks for your help
You could handle your QDialog on a separate class, and then make them interact only, the structure might change a bit, but you can see if it's a viable answer:
import sys
from PySide2.QtWidgets import *
class MyWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
button = QPushButton("Dialog")
button.clicked.connect(self.open_dialog)
self.setCentralWidget(button)
def open_dialog(self):
dialog = MyDialog()
dialog.show()
dialog.exec_()
class MyDialog(QDialog):
def __init__(self):
QDialog.__init__(self)
button = QPushButton("Close")
button.clicked.connect(self.close_dialog)
layout = QHBoxLayout()
layout.addWidget(button)
self.setLayout(layout)
def close_dialog(self):
self.close()
if __name__ == "__main__":
app = QApplication()
m = MyWindow()
m.show()
sys.exit(app.exec_())
Just notice that you should include the setUp step on each class.
Hope it helps.
To put the dialog into a separate class didn't work for either.
Every time the Dialog.close() event was called, it closes the whole application.
What worked for me, was to use hide() instead

PyQt4 How keep a QWidget always on top?

I'm using PyQt4 with python 2.7 on Windows7
I have a QWidget that I want to stay above the QMainWindow while clicking on the main. The idea is that the main will contain a series of 'edit' buttons that will open the edit widget, while the edit widget refreshes with info contained on the main. I don't particularly care if either is "always on top" as long as the widget stays in front of the main window.
There are a couple of questions that address this topic, but I'm not seeing an answer that works for my specific use case. One deals in widgets but provides an answer only for the app main window (widget stays above other environmental windows but falls behind the application main window when clicking on the main), and the other addresses Qt generally but not a pythonic example:
PyQt: Always on top
How keep a QWidget always on top?
Here is the code I have so far:
from PyQt4 import QtCore, QtGui
class Ui_MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self, None, QtCore.Qt.WindowStaysOnTopHint)
self.setWindowTitle("MainWindow")
self.resize(400, 300)
class Ui_Widget(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self, None, QtCore.Qt.WindowStaysOnTopHint)
self.setWindowTitle("Widget")
self.resize(400, 300)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
MainWindow = Ui_MainWindow()
MainWindow.show()
Widget = Ui_Widget()
Widget.show()
sys.exit(app.exec_())
If you want Ui_Widget to always be on top of Ui_MainWindow, Ui_Widget must be a child of Ui_MainWindow and the flag Qt::Dialog must be activated as shown below:
from PyQt4 import QtCore, QtGui
class Ui_MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setWindowTitle("MainWindow")
self.resize(400, 300)
class Ui_Widget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowFlags(self.windowFlags() | QtCore.Qt.Dialog)
self.setWindowTitle("Widget")
self.resize(400, 300)
self.move(200, 150)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
MainWindow = Ui_MainWindow()
MainWindow.show()
Widget = Ui_Widget(MainWindow)
Widget.show()
sys.exit(app.exec_())

Categories