How to start project with TabWidget without QWidget - python

Everytime you create new project from Qt Creator there is on top QWidget which you can delete.
You can of course write the code manually as this:
app = QApplication(sys.argv)
ex = Main()
sys.exit(app.exec_())
where Main class is inherited from QTabWidget and everything works.
class Main(QTabWidget):
def __init__(self):
super().__init__()
Is there any way how to achieve this from Qt Designer?
How can i delete QWidget and put QTabWidget on top of hierarchy?

When you create a GUI with Qt Designer you can choose the widget that you take as base as shown in the following image:
Generally we choose from the first option templates/forms, but we can also choose from Widgets (Second option)
In this second option we can choose as a basis for QTabWidget.

Related

What is the best way to add regular widgets on top of a QGraphicsView?

I'm researching refactoring a tkinter app that currently uses tkinter.Canvas. The Canvas reacts to user input by creating windows over the canvas, which are made of regular tkinter widgets.
I haven't seen the equivalent method in QGraphicsView to tkinter.Canvas.create_window, wihch creates a canvas bound item that can then be used for building a regular interface.
Basically I'm looking for the right way to, say, right click on the View and get a popup window on top that I can deal with. Hopefully not bound to the scene, either, so that if I have multiple views on the scene the window only appears over the original View.
Because I'm new to Qt I'm out of my depth. Perhaps the widget that contains the View can receive the clicking event and proceeds to layout another widget in absolute terms over the QGraphicsView?
Any help is appreciated. Thanks!
I Found how to do it:
import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
QApplication,
QGraphicsScene,
QGraphicsView,
QGraphicsWidget,
)
app = QApplication(sys.argv)
scene = QGraphicsScene()
view = QGraphicsView(scene)
view.resize(400, 300)
window = QGraphicsWidget(None, Qt.Window)
window.resize(200, 200)
scene.addItem(window)
view.setScene(scene)
view.show()
sys.exit(app.exec())
Notice that unlike tkinter although you can add a regular widget to the QGraphicsScene directly with scene.addWidget, there are some limitations.
The method scene.addWidget returns a QGraphicsProxyWidget which is what can be positioned on the scene. And the layout of these widgets are different to the ones of regular widgets.

QDialog as central widget layout in QMainWindow

Can you display a QDialog as the central widget of a QMainWindow in Python? If so, how would you do it? I am trying to find the easiest way to add a menu bar which is only available with QMainWindow to my understanding. Is it possible to connect the two together?
tl;dr
No, but you can add a menubar to a layout set for the QDialog, using setMenuBar() or even by adding the menubar as you would do for any other widget, just by doing that on "top" of that layout.
Is it possible?
The technical answer is "yes": since QDialog is a QWidget, you can just use setCentralWidget() as you would do with any other QWidget subclass.
The real answer is "NO: don't do it!".
QDialog, just like QMainWindow, is intended to be a top level widget (aka, a "window"), so it should never be added as a child of a widget or in its layout.
There are very few exceptions to that:
when using systems that are intended as possible "containers" of windows, which are:
QMdiArea;
the Graphics View framework;
in very special cases (such as attempting custom layouts of dock widgets), for which you should really know what you're doing, be really aware of the limitations and aspects related to the UX;
Most importantly, QDialog has specific flags and event filters that might be problematic.
For instance, take this simple example:
mainWindow = QMainWindow()
dialog = QDialog()
layout = QVBoxLayout(dialog)
layout.addWidget(QPushButton())
mainWindow.setCentralWidget(dialog)
mainWindow.show()
Now, just press Esc, and you'll see that the dialog disappears.
The same happens by adding a QDialog as a child of any widget, clearly meaning that it should never be done (unless when using the "container" systems listed above).
This is one of the many reasons for which some tutorials on YouTube should be completely disregarded (since they provide terrible suggestions, like adding a QMainWindow or QDialog to a QStackedWidget).
The solution
Actually, it's very simple: just add the menubar to the top level layout of the dialog, just like you would do for any other widget.
Besides, consider that all Qt layout managers inherit from QLayout, which has a very basic and important function that is often ignored: setMenuBar().
Tells the geometry manager to place the menu bar widget at the top of parentWidget(), outside QWidget::contentsMargins(). All child widgets are placed below the bottom edge of the menu bar.
Note that this is actually a "convenience" feature, and it only works for the "top level" layout: if you add the menubar to a nested layout, it won't be considered in the whole size hint/policy computation, and it will be probably shown above (in the z stacking level) any other widget near it.
Also note that, for obvious reasons, this cannot be done from Designer. If you have a QDialog created in Designer and you want to add a menubar, you have to do it by code.
Assuming that you properly set a top level layout (as you should always do) for your dialog in Designer:
from myDialog import Ui_MyDialog
from PyQt5.QWidgets import *
class MyDialog(QDialog, Ui_MyDialog):
def __init__(self):
super().__init__()
self.setupUi(self)
self.menuBar = QMenuBar()
self.layout().setMenuBar(self.menuBar)
self.fileMenu = self.menuBar.addMenu('File')
self.someAction = self.fileMenu.addAction('Some action')
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
dialog = MyDialog()
dialog.exec()

PyQt5: create multiple views with designer and connect them in one app

I have completed a simple app in PyQt5, where I did design the UI in QT designer, converted in py code with pyuic5and ran it via python interpreter.
Now I would like to add another UI view, although I am not familiar with PyQt5, and most of the tutorial I found are only mentioning one view.
If I was using Visual Studio for example, I could create a new form, and use show and hide methods to display them, when I press a button for example, but I am not sure how to do the same with PyQt5.
Converted code from pyuic5 include also the if __name__ == "__main__" function, which create the instance and run the app, so is it enough to just take anything above it, to get the UI data only? And how do I create a view from that, so I can show and hide it as needed? Thanks.
EDIT:
Got a bit further, since I found a different way to load UI files. Seems that PyQt has a method that is able to load a UI file directly, instead of convert it in python code. This means that I can create a class that is a subclass of the type of window that I am using (example: QApplication, QMainWindow, QWidget and so on), and I can access that object as if it was a form in Visual Studio.
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow
from PyQt5.uic import loadUI
class UIObject(QMainWindow):
def __init__(self):
super(UIObject, self).__init__()
loadUI('mainapp.ui', self)
self.mybutton1.clicked.connect(self.printhello)
def printhello():
print("hello")
app = QApplication(sys.argv)
mainview = UIObject()
mainview.show()
sys.exit(app.exec_())
This will load the UI file and show it on screen; I assume that I can use the same construct to load multiple ui files and show then or hide them as I do in Visual studio? Seems straightforward but not knowing much about QT or PyQT, I am not sure why this way to handle ui files is not more commonly advertised in tutorials; I found it by chance while reading the docs.
Found the solution, mixing up various answers and posts from different forums.
You create a first class as QMainWindow, in the __init__ you use loadUi to load the QT designer file. Then you create a second class, which is the one that hold your second form/view, and in the __init__ you pass as parameter the parent view (your first class, or whatever other you may need); so you can hide the main view and show the second view when clicking a button. When you close the secondary view, the previous view will show up again.
You can add as many different windows you want; the trick is to always pass the parent on each of them and remember to show/hide them accordingly. Much more complex than Visual Studio forms, but it is doable.
class FirstForm(QMainWindow):
def __init__(self):
super(FirstForm, self).__init__()
loadUi('firstform.ui', self)
self.button1.clicked.connect(self.openOtherForm)
def openOtherForm(self):
self.hide()
otherview = SecondForm(self)
otherview.show()
class SecondForm(QDialog):
def __init__(self, parent=None):
super(SecondForm, self).__init__(parent)
loadUi('secondform.ui', self)
self.button2.clicked.connect(self.goBackToOtherForm)
def openOtherForm(self):
self.parent().show()
self.close()
app = QApplication(sys.argv)
main = FirstForm()
main.show()
sys.exit(app.exec_())

PySide : How to get a QTabWidget to resize with the window?

I'm quite new to Python, and I'm developing an app with the PySide library.
I have a QTabWidget in which I will later define buttons/labels/... with some layouts. The question is simple : I'd like to have my active tab filling the window horizontally and vertically, even when I resize the window. For now its size is determined by the widgets I put in. Even with addStretch(1) in a QHBoxLayout or QVBoxLayout I can't get it to expand.
Is there an easy way to do this (I'm not a Python expert yet) ?
Any help will be highly appreciated.
If your main window is QMainWindow then it is enough to insert QTabWidget with mainwindow->setCentralWidget() - by default it will use all available space.
In other case, to have QTabWidget to follow the resizing/geometry change of parent widget, it is enough to make some layout on the parent widget and just insert QTabWidget there.
Code is approx (in Qt):
QWidget * dialog = ...
QTabWidget * tabs = new QTabWidget;
QVBoxLayout * vbox = new QVBoxLayout;
vbox->addWidget(tabs);
dialog->setLayout(vbox);
dialog->show();

modelPanel (Maya) in QT UI using PySide

I am having an issue parenting a modelPanel (Viewport) into a predefined space in a QT Ui created in Designer. When I try to parent the modelPanel and run the script in Maya, it immediately crashes.
Example:
Create a new window in Qt Designer, and drag and drop a vertical layout in the window and save the ui. In the python class when do the parenting i do it as follows:
pm.modelPanel('modelPanelA', p = 'verticalLayout')
The window is drawn and I see the viewport, BUT the window is not scaleable. Which it has to be. So back in Qt Designer I got to Form > Lay Out as Grid. Now the vertical layout is scalable. I save the UI, reload the class, and create the window. Maya crashes! Why?

Categories

Resources