using layouts in qwidget - linux

I am using qt 4.7 on RHEL 6.0. I am finding very difficut use te layouts. Here is my code.
I have two widgets that are arranged using grid layout.
QWidget *topWidget = new QWidget();
QWidget *bottomwidget = new QWidget();
These two widgets are contained in a QFrame. So now i wanted to add a QPhonon::VideoPlayer widget exactly in b/w the above two widget. For adding am doing like this..
VideoPlayer *vPlayer = new VideoPlayer(Phonon::VideoCategory,this);
vPlayer->setSizePolicy(QSizeHint::Expanding, QSizeHint::Expanding);
QVBoxLayOut *layOut = (QVBoxLayOut*)ui->frame->layout();
layout->insertWidget(1,vPlayer,5,Qt::AlignCenter);
the size of all topWidget, boottomWidget are 768 and 576 which is the size of the D1 video frame. I am playing a video in vPlayer phonon widget. But what I am seeing is vPlayer size is very small and video size also small. Means to say I am not seeing the 768/576 size video. Can somebody help me? Any help would be appreciated.

1)
QVBoxLayOut *layOut = (QVBoxLayOut*)ui->frame->layout();
Do not use C-style casts! Use
dynamic_casr<QVBoxLayout*>(ui->frame->layout())
2)Try to vPlayer->setMinimumSize(QSize(500, 500))
3)And as far as I know Qt, if you want to change GUI or construct complicated ones, then it is preferred to construct GUI's by itself, not with QtDesigner.

Related

How do I make a PyQt QLineEdit widget narrower than the default size of 17 x's when using QT Designer?

When I put Qt widgets in a QHBoxLayout layout using QT Designer, there seems to be a minimum width for QLineEdit widgets of 17 x's, at least if this is the current source code:
https://github.com/qt/qtbase/blob/dev/src/widgets/widgets/qlineedit.cpp
I cannot find a way to make PyQt5 lay those widgets out so they will be narrower than this default, but still change size if the font is changed.
As an example, a QComboBox will be automatically laid out so that it is just wide enough to display the longest text that is entered as a possible value. If the longest text entered for a combobox in Designer is 5 characters, the combobox will be laid out as quite narrow compared to the minimum QLineEdit width. How can I configure a QLineEdit with a number of characters so that it is always wide enough for that many characters, whatever the font is set to, and no wider, using just QT Designer? I know in Designer I can enter maxLength, which will limit the maximum number of characters that can be entered/displayed, but that setting of course has no effect on the layout.
I have some text boxes that will never have more than 5 characters in them, for example, and the layout with Designer makes them at least 3 times wider than I will ever need. This is using the default "Expanding" horizontal policy, but I have tried many combinations of horizontal policy and values for minimum size or base size. I want to allow for people to have different font sizes, so I cannot safely set a maximum pixel size and I cannot safely set a fixed horizontal size. The handling for QComboBoxes is precisely what I want for QLineEdits.
This is all in python using the latest versions of PyQt5 available on Pip, pyqt5 5.15.6 and pyqt5-qt5 5.15.2.
The size hint of QLineEdit is computed considering various aspects, most of them using private functions that are not exposed to the API, and the "x" count is hardcoded, meaning that this cannot be achieved directly from Designer, and can only be done through subclassing.
While we could try to mimic its behavior to implement a custom character size, I believe it is unnecessary for simple cases, so I simplified the concept by taking the default size hint and adapting the width based on the difference between the custom character hint and the default 17 "x" count.
class CharHintLineEdit(QtWidgets.QLineEdit):
_charHint = 17
#QtCore.pyqtProperty(int)
def charHint(self):
return self._charHint
#charHint.setter
def charHint(self, chars):
chars = max(1, chars)
if self._charHint != chars:
self._charHint = chars
self.updateGeometry()
def changeEvent(self, event):
super().changeEvent(event)
if event.type() in (event.FontChange, event.StyleChange):
self.updateGeometry()
def sizeHint(self):
hint = super().sizeHint()
if self._charHint != 17:
# the 17 char width is hardcoded in Qt and there is no way to
# retrieve it, it might change in the future, so, just to be safe,
# we always set an arbitrary minimum based on half the height hint
charSize = self.fontMetrics().horizontalAdvance('x')
hint.setWidth(max(hint.height() // 2, hint.width() +
charSize * (self._charHint - 17)))
return hint
if __name__ == '__main__':
import sys
from random import randrange
app = QtWidgets.QApplication(sys.argv)
test = QtWidgets.QWidget()
layout = QtWidgets.QHBoxLayout(test)
for i in range(5):
charHint = randrange(5, 15)
le = CharHintLineEdit(charHint=charHint, placeholderText=str(charHint))
layout.addWidget(le)
test.show()
sys.exit(app.exec())
With the above code, you can use the custom widget in Designer by adding a standard QLineEdit and promoting it with the class name and relative python file (without the file extension) as header. You can also set the charHint as a dynamic property in Designer, and it will be properly set for the widget when the UI is loaded.

Add a QWidget inside a QFrame

I'm developing a desktop software using Python3 and QtDesigner for the Graphic User Interface.
My problem is the seguent: i'm trying to automate the creation of many QRadioButtons over a QFrame (The RadioButtons must stay inside the frame [as...children?]).
Now, i see that i can only create new widgets inside a Layout (e.g. "MyLayout.addWidget(QRadioButton")) and it's not possible to do something like "MyFrame.addWidget(QRadioButton)". I need these widgets inside the frame cause then i can place them in the correct position with "MyRB.move(X,Y)".
With QtDesigner is possible to place many Widgets (like RadioButtons) in a frame that has a 'broken layout' so i can choose X,Y coordinates but i need to create and place a variable number of those.
Is it possible to create Qwidgets inside a QFrame?
[EDIT]
according to musicamante's comment, i got that's a parent problem.
I tried to insert a Label and a RadioButton in the main window:
def __init__(self):
super().__init__()
uic.loadUi('DSS_GUI2.ui',self) # i load the GUI with QtDesigner
LB1 = QLabel('MyLabel',self)
RB1 = QRadioButton('MyRadioButton',self)
...
This very simple example works fine but when i try to add a Label through a function
def myFunction(self):
LB1 = QLabel('MyLabel')
LB1.setObjectName('LABEL_1')
LB1.setParent(self.myFrame)
the Widget is inserted but it is not visible, in fact adding this lines to check his presence
WidgetList = self.myFrame.findChildren(QLabel)
for item in WidgetList:
print(item.objectName())
i see in the console that the Label is there.
Do you know why it's not visible?
Try
def myFunction(self):
LB1 = self.sender()
LB1.QLabel('MyLabel')
LB1.setObjectName('LABEL_1')
LB1.setParent(self.myFrame)
You can call self.myFunction() in parent.
If you wanted to pass label, you could:
def myFunction(self, label):
LB1 = self.sender()
LB1.QLabel(label)
LB1.setObjectName(label)
LB1.setParent(self.myFrame)

Tkinter: pack()ing frames that use grid()

I am working on a UI for a data-display applet. I started with a tutorial and have since expanded it well beyond the scope of the tutorial, but some legacy bits remain from the tutorial that are now causing me difficulty. In particular relating to pack() and grid().
Following the tutorial I have defined a class Window(Frame) object, which I then declare as app = Window(root) where root = Tk(). Within the Window object is an initializing function def init_window(self), where my problems arise. Here is the relevant code in init_window():
def init_window(self):
self.master.title('Data Explorer') #changing the widget title
self.pack(fill=BOTH,expand=1) # allow widget to take full space of root
# Initializing a grid to place objects on
self.mainframe = Frame(root)
self.mainframe.grid(column=0,row=0, sticky=(N,W,E,S) )
self.mainframe.columnconfigure(0, weight = 1)
self.mainframe.rowconfigure(0, weight = 1)
self.mainframe.pack(pady = 10, padx = 10)
where the object self.mainframe contains a number of data selection dropdowns and buttons later on.
If I understand what this code is expected to do: it sets up the full window to be pack()ed with various frames. It then initializes a frame, self.mainframe, and within that frame initializes a grid(). Thus pack() and grid() do not collide. This setup was built by following the aforementioned tutorial.
This works correctly on my computer where I am developing the applet. However, when a collaborator compiles, they receive
_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack
on the line self.mainframe.grid(...). I have replaced the mainframe.pack() command with a mainframe.place() command, but this has not resolved the issue (since his compile does not reach that point); I have not figured out a way to remove the self.pack() command without causing all other elements of my UI to vanish.
Can anyone help us understand what is going wrong? For reference, we are both using MacOS, and compiling with Python3. I can provide additional information as requested, within limits.
The error is telling you exactly what is wrong. You can't use grid on a widget in the root window when you've already used pack to manage a widget in the root window.
You wrote:
It then initializes a frame, self.mainframe, and within that frame initializes a grid()
No, that is not what your code is doing. It is not setting up a grid within the frame, it's attempting to use grid to add the widget to the root window.
First you have this line of code which uses pack on a widget in the root window:
self.pack(fill=BOTH,expand=1)
Later, you try to use grid for another window in the root window:
self.mainframe = Frame(root)
self.mainframe.grid(column=0,row=0, sticky=(N,W,E,S) )
The above isn't setting up a grid within self.mainframe, it's using grid to add the widget to the root window.
You need to use one or the other, you can't use both for different windows that are both direct children of the root window.
In other words, you're doing this:
self.pack(fill=BOTH,expand=1)
self.mainframe.grid(column=0,row=0, sticky=(N,W,E,S) )
but since both self and self.mainframe are a direct child of the root window, you can't do that. You need to either use pack for both:
self.pack(fill=BOTH,expand=1)
self.mainframe.pack(...)
... or grid for both:
self.grid(...)
self.mainframe.grid(column=0,row=0, sticky=(N,W,E,S) )

How do I set the minimum size of a Gtk ButtonBox child?

I'm trying to set the minimum size of the buttons in this GtkButtonBox. Currently they seem to be fixed - approx 85 pixels I think.
Is this possible?
If not, is there another way in Gtk to get two small sized buttons to snuggle together like in the above picture rather than having them appear to be two separate buttons? For example GtkStackSwitcher may be something I could use but there doesn't appear to be a way to respond to click events for a button.
I've used this test program to create the above (Ubuntu 14.04, Gtk+3.10 and Python3):
from gi.repository import Gtk
import sys
class MyWindow(Gtk.ApplicationWindow):
def __init__(self, app):
Gtk.Window.__init__(self, title="example", application=app)
self.set_default_size(350, 200)
self.set_border_width(10)
hbox = Gtk.ButtonBox.new(Gtk.Orientation.HORIZONTAL)
hbox.set_layout(Gtk.ButtonBoxStyle.EXPAND)
button = Gtk.Button(label="a")
hbox.add(button)
button2 = Gtk.Button(label="b")
hbox.add(button2)
self.add(hbox)
class MyApplication(Gtk.Application):
def __init__(self):
Gtk.Application.__init__(self)
def do_activate(self):
win = MyWindow(self)
win.show_all()
def do_startup(self):
Gtk.Application.do_startup(self)
app = MyApplication()
exit_status = app.run(sys.argv)
sys.exit(exit_status)
With regards to a question about the desktop environment I'm using.
I've tried Mate, Unity and Gnome-Shell. All work the same way. I've removed the title and those controls. Still the same thing happens. To me this looks more like a GTK issue.
I believe that GtkButtonBox imposes some layout constraints on its buttons that you may not want here. Try using buttons in just a regular GtkGrid, but give them the GTK_STYLE_CLASS_LINKED CSS class.
For each button, do:
button.get_style_context().add_class(Gtk.STYLE_CLASS_LINKED)

Show QMainwindow in the middle of the screen

I want show my project main window in the middle of the screen . when i call "self.show()" then the window show in the middle of the screen .
I know you have already solved it, but I make this answer for those who have the same question. I post it mainly because you asked for pyQt and the other answer is for Qt (C++).
I found a workaround here: https://bashelton.com/2009/06/pyqt-center-on-screen/
Is so simple and works perfectly, I transmit it..
class ExampleWindow (QtGui.QMainWindow):
def __init__ (self, parent=None):
'''constructor'''
QtGui.QMainWindow.__init__(self, parent)
self.setGeometry(0, 0, 650, 550)
self.setWindowTitle("My Example Application")
self.centerOnScreen()
def centerOnScreen (self):
'''centerOnScreen()
Centers the window on the screen.'''
resolution = QtGui.QDesktopWidget().screenGeometry()
self.move((resolution.width() / 2) - (self.frameSize().width() / 2),
(resolution.height() / 2) - (self.frameSize().height() / 2))
Good luck!
First I would recommend against trying to force a window position on your users and let the system's window manager decide where it should go. If you really insist on positioning it yourself (perhaps you are programming for a kiosk), you can find some information here in a previous question on stackoverflow.
A slightly more elegant calculation for doing this is discussed here.
When doing this calculation, it is important that it is done at the correct time, after Qt has resized everything and just before it is shown on screen. One method that might help is to create a one-shot timer and do the screen positioning in the slot for the timer.
This worked for me in Pyqt5:
from PyQt5.QtWidgets import *
qtRectangle = self.frameGeometry()
centerPoint = QDesktopWidget().availableGeometry().center()
qtRectangle.moveCenter(centerPoint)
self.move(qtRectangle.topLeft())

Resources