PyQt - QWidget - Show Title bar only - python

I am opening multiple files in my application. For big files it takes few seconds to open, Hence I am displaying a QWidget with status of opened files.
The Main application passes a signal to qwidget and titlebar gets updated.
I used setWindowFlags(Qt.WindowTitleHint) to get rid of minimize/maximize buttons.
Is it the right way to do it?
Is it possible for QWidget to show title bar only?
#This is the method for reading files in the main class
#Some other method passes filenames to this method
def readfiles(self,filenames):
fopenstins=FileOpenStatusWidget()
fopenstins.show()
for i in range(len(filenames)): # Read files one by one
self.emit(SIGNAL('fopenstsig'),i+1,len(filenames))
#### More Code for reading files#####
class FileOpenStatusWidget(QtGui.QWidget):
def __init__(self):
super(FileOpenStatusWidget, self).__init__()
self.connect(main,SIGNAL('fopenstsig'),self.qwrtt)
self.layout = QtGui.QVBoxLayout()
self.status=QtGui.QLabel()
self.layout.addWidget(self.status) # This does not work -- Window remains blank
self.setWindowFlags(Qt.WindowTitleHint)
self.setLayout(self.layout)
def qwrtt(self,openedfiles,totalfiles):
self.status.setText('Opening File '+str(openedfiles)+'/'+str(totalfiles))
if openedfiles==totalfiles:
self.hide()
else:
self.setWindowTitle(self.status.text())

Use a combination of flags: Qt.CustomizeWindowHint | Qt.WindowTitleHint.
Window icon and close button are controlled by the Qt.WindowSystemMenuHint, which is added by default. Qt.CustomizeWindowHint disables all default hints.

Related

Unreal Pyside6 widgets wont get removed by garbage collector

I am unable to remove PySide6 widgets in Unreal 5 python. Will describe the code first:
I have my ArtToolsUI class inheriting from QMainWindow. In this class I set some basic stuff like groupboxes, layouts etc.:
class ArtToolsUI(QMainWindow):
def __init__(self):
super().__init__()
self.setAttribute(Qt.WA_DeleteOnClose, True)
self._app = self._get_qt_app()
self.resize(600,400)
self.editor_tools_buttons = [] #for showcase this has no widgets in it
self._main_widget = self._set_layouts()
def _get_qt_app(self):
qt_app = QApplication.instance()
qt_app.setQuitOnLastWindowClosed(True)
return qt_app
def get_v_layout(widgets):
widgets = make_list(widgets)
layout = QVBoxLayout()
layout.setObjectName("vert_layout")
for widget in widgets:
layout.addWidget(widget)
return layout
def _set_layouts(self):
default_grpbox_names = {"tools":self.editor_tools_buttons}
all_grp_boxes = []
for key in default_grpbox_names:
layout = get_v_layout(default_grpbox_names[key]) # right now this just returns empty QVBoxLayout
new_grp_box = QGroupBox(title=key)
new_grp_box.setAttribute(Qt.WA_DeleteOnClose, True)
new_grp_box.setLayout(layout)
all_grp_boxes.append(new_grp_box)
main_layout = get_v_layout(all_grp_boxes)
main_widget = QWidget()
main_widget.setObjectName("tat_main_widget")
main_widget.setLayout(main_layout)
self.setCentralWidget(main_widget)
return main_widget
I also implemented function for removing all widgets in this unreal python session. This method is called from different module.
def _remove_widgets():
qt_app = QApplication.instance()
if qt_app != None:
all_qt_widgets = qt_app.allWidgets()
for widget in all_qt_widgets:
widget.setParent(None)
widget.close()
widget.deleteLater()
This _remove_widgets() method goes through all existing widgets, which should be destroyed, but for some reason only my ArtToolsUI main window is getting destroyed and all other widgets are still hanging around in the memory.
On the other side when I manually click on the X button to close the window it closes everything.
Does anyone know what might be the problem?
Ok I think I figured it out.
When running PySide6 on unreal you actualy cannot start your own QT event loop ( if you do, Unreal Editor will freeze and wait till you end your window). QT somehow finds unreal GUI event loop, which is responsible for everything .. except answering deleteLater().
Only two ways ( I found) for deleting UI are:
When user clicks on X button to end the Window -> This automatically ends and removes all widgets in that window.
When calling QApplication.closeAllWindows() -> This calls all windows, but definitelly better than if they stay in memory.
Both ways seem to bypass deleteLater() functionality, as documentation for deleteLater() says:
The object will be deleted when control returns to the event loop.
At the end I ended up with this functionality:
I am not deleting dialogs, I just hide them on close().
Then when creating them I ask if there are dialogs with my specific object name (object name is class property at every window I have)
This will prevent spawning multiple widgets ( 10k widgets is aprox. 1.2GB RAM)
ADD: There is also possibility to use self.setAttribute(Qt.WA_DeleteOnClose, True) on closing. This will delete dialog from memory as well.

Single window mode with the ability to open multiple dialogs at once in PyQt5?

I'm using the below code in PyQt5/PySide2 in order to create a single mode window application, when I open a new dialog:
dialog.setWindowModality(QtCore.Qt.ApplicationModal)
dialog.setWindowFlags(QtCore.Qt.Tool)
But I need another mode which I didn't managed to solve it by reading the docs, imagine we've got a QMainWindow and we have 4 buttons on the main window, I want to open the corresponding dialogs when clicking on the buttons, but the idea is this:
By using the above piece of code, the parent window (Main) will be blocked, so it's not possible to click on the other buttons to open the dialogs.
Prevent the application from opening the dialogs which are already opened.
Ok, in the main window you can create functions that open their own window for example:
main window file:
def open_add_user_window(self):
# import the class of window dialog that you create, example:
from new_user_dialog import NewUserDialog # the class you create
# Create a variable to store the object of the NewUserDialog class
# in this case self means the instances of the main window
window = NewUserDialog(self)
# then call the method show() of the object window
window.show()
New User window file (child window):
# in the constructor:
# parent is the parameter that stored the main window instance
def __init__(self, parent=None):
# with super call the constructor of the QDialog class an passed like argument the
#parent
super().__init__(parent)
# This is important if you don't put this code the child window will appear like
#sticked on the main window.
self.setWindowFlag(Qt.Window)

QFileDialog opens in new window while adding it to QHBoxLayout

My issue is that when I am adding QFileDialog to QVBoxLayout it opens in new window. Below is the code which produces my problem.
from PyQt5.QtWidgets import QVBoxLayout, QFileDialog, QPushButton, QWidget
class MainWindow(QtWidgets.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("My own MainWindow")
self.fileDialog = QFileDialog()
self.confirmAction = QPushButton("Press me", self)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.fileDialog)
mainLayout.addWidget(self.confirmAction)
self.setLayout(mainLayout)
According to the docs:
Window flags are a combination of a type (e.g. Qt::Dialog) and zero or
more hints to the window system (e.g. Qt::FramelessWindowHint).
If the widget had type Qt::Widget or Qt::SubWindow and becomes a
window (Qt::Window, Qt::Dialog, etc.), it is put at position (0, 0) on
the desktop. If the widget is a window and becomes a Qt::Widget or
Qt::SubWindow, it is put at position (0, 0) relative to its parent
widget.
So these flags are used to vary the behavior of the widget, for example to convert it into a window, a dialog, a tooltip, and so on.
In the docs gives the following list:
Qt::Widget: This is the default
type for QWidget. Widgets of this type are child widgets if they have
a parent, and independent windows if they have no parent. See also
Qt::Window and Qt::SubWindow.
Qt::Window: Indicates that the
widget is a window, usually with a window system frame and a title
bar, irrespective of whether the widget has a parent or not. Note that
it is not possible to unset this flag if the widget does not have a
parent.
Qt::Dialog :Window Indicates that the widget is a
window that should be decorated as a dialog (i.e., typically no
maximize or minimize buttons in the title bar). This is the default
type for QDialog. If you want to use it as a modal dialog, it should
be launched from another window, or have a parent and used with the
QWidget::windowModality property. If you make it modal, the dialog
will prevent other top-level windows in the application from getting
any input. We refer to a top-level window that has a parent as a
secondary window.
Qt::Sheet: Window Indicates that the
window is a Macintosh sheet. Since using a sheet implies window
modality, the recommended way is to use QWidget::setWindowModality(),
or QDialog::open(), instead.
Qt::Drawer: Window Indicates
that the widget is a Macintosh drawer.
Qt::Popup : Window Indicates that the widget is a pop-up top-level window, i.e.
that it is modal, but has a window system frame appropriate for pop-up
menus.
Qt::Tool: Window Indicates that the widget is a
tool window. A tool window is often a small window with a smaller than
usual title bar and decoration, typically used for collections of tool
buttons. If there is a parent, the tool window will always be kept on
top of it. If there isn't a parent, you may consider using
Qt::WindowStaysOnTopHint as well. If the window system supports it, a
tool window can be decorated with a somewhat lighter frame. It can
also be combined with Qt::FramelessWindowHint.
On Mac OS X, tool windows correspond to the Floating class of windows.
This means that the window lives on a level above normal windows; it
impossible to put a normal window on top of it. By default, tool
windows will disappear when the application is inactive. This can be
controlled by the Qt::WA_MacAlwaysShowToolWindow attribute.
Qt::ToolTip:Window Indicates that the widget is a
tooltip. This is used internally to implement tooltips.
Qt::SplashScreen: Window Indicates that the window is a
splash screen. This is the default type for QSplashScreen.
Qt::Desktop:Window Indicates that this widget is the
desktop. This is the type for QDesktopWidget.
Qt::SubWindow: Indicates that this widget is a sub-window,
such as a QMdiSubWindow widget.
In your case we must change the behavior of Qt::Dialog to Qt::Widget, in the following code I show the code that does it:
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("My own MainWindow")
self.fileDialog = QFileDialog(self)
self.fileDialog.setOption(QFileDialog.DontUseNativeDialog)
self.fileDialog.setWindowFlags(Qt.Widget)
self.confirmAction = QPushButton("Press me", self)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.fileDialog)
mainLayout.addWidget(self.confirmAction)
self.setLayout(mainLayout)
Screenshot:
I've been looking into this myself, dissatisfied with the "just use non-native dialogs" bit. I've been hacking around in the KDE platform file dialog implementation and have gotten (stuck) pretty close to what I'd want.
The only point of attach I've found is just before the dialog will actually be shown; before that there seems to be no way to know the actual parent widget. But there we can:
find the parent QWidget (from the parent QWindow)
from that, obtain the (first) (user-side) QFileDialog instance
if the parent QWidget has a layout, replace the found QFileDialog instance with our own dialog
save the original user-side QFileDialog instance
in the dtor, either restore the original QFD in the layout, or call deleteLater() on it (and set it to NULL in case the action causes recursive calling of the dtor).
Glitches:
- dialogs may end up with 2 sets of OK/Cancel/etc. buttons
- if not, these buttons may actually close only the embedded QFD and not the enclosing dialog (seen with the python example linked above)
- resizing works but the saveSize/restoreSize mechanism doesn't
- AFAICT all signals aren't connected properly (the preview in the Scribus open-file dialog doesn't react to selecting a file as it should). File opening does work though.
Full patch here on this BKO ticket:
https://bugs.kde.org/show_bug.cgi?id=404833#c15
Evidently this is only useful for hackers and software that can ship its own platform theme plugin (which is where the KDE platform file dialog comes from). Fortunately those plugins tend to be relatively small.

How to show Qt.Tool window with minimize/maximize windows controls?

I have...
class ToolWindow(QtWidgets.QMainWindow):
"""Generic window to be used as non-modal tool
Usage:
tool_win = ToolWindow()
layout = QtWidgets.QHBoxLayout()
button = QtWidgets.QPushButton('hello')
layout.addWidget(button)
tool_win.setup(layout)
button.released.connect(lambda: print('hello'))
tool_win.show()
"""
def __init__(self):
super(ToolWindow, self).__init__()
def setup(self, layout,
window_title='Untitled', object_name=None, tool=True):
"""Setup tool window"""
if tool:
self.setWindowFlags(QtCore.Qt.Tool)
self.widget = QtWidgets.QWidget()
self.widget.setLayout(layout)
self.setCentralWidget(self.widget)
self.setWindowTitle(window_title)
def closeEvent(self, event):
"""Delete object when closed"""
self.deleteLater()
However, I wish to add the typical maximize and minimize window controls to the window. I've attempted to add the following to the ToolWindow class without success (the tool window still doesn't show the maximize/minimize window controls):
self.setWindowFlags(self.windowFlags() |
QtCore.Qt.WindowSystemMenuHint |
QtCore.Qt.WindowMinMaxButtonsHint)
Is it possible to add these controls to a tool window?
Alternatively, can I create a non-modal window but which always sits atop my parent application and which shows the maximize/minimize window controls?
Please note, I don't want this tool window staying on top of ALL windows on my system. I only want it to always stay on top of my application.
You should be able to just use the QMainWindow class without any flags. As long as the tool window is a child of the primary application window, it will stay on top of it (but not windows from other applications, like it would if you set the "Window Stays On Top" flag).
You'll need to change your __init__ to accept parent arguments
def __init__(self, parent):
super(ToolWindow, self).__init__(parent)
If you have multiple Tool Windows and you want them to stay on top in a specific order, you can call my_tool_window.raise_() to bring it to the top of the z-order.
Qt ships with a window flags example. You may want to check that out to see how the different flags affect the window display and behavior.

How to pass along menu shortcuts from child widget holding focus in PyQt4?

I have a QMainWindow with a menu bar, including menu items for Save, Open and Quit with the usual shortcuts. It creates a QTableWidget that lists a bunch of different categories from which the user can choose (at his option).
If the user clicks into the QTableWidget to change categories, the widget takes the focus. That's mostly what I want, but unfortunately it also seems to steal the menu shortcuts, so that pressing Ctrl+S no longer triggers the save.
I experimented with keyPressEvent to solve this, but it seems like overkill even if I do get it working. Isn't there a way to delegate all the control/menu keys back to the QMainWindow ?
There must be an issue with how you are creating your QMenuBar. Here is an example that works just fine for me. The Save continues to function regardless of focus being in the table:
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.resize(640,480)
menuBar = self.menuBar()
menu = menuBar.addMenu("&File")
action = menu.addAction("&Save", self.doAction)
action.setShortcuts(QtGui.QKeySequence.Save)
self.view = QtGui.QTableWidget(5,5)
self.setCentralWidget(self.view)
def doAction(self):
print "Save"

Categories