qt grow-only size policy - qt

I have QLabel and this width shrink to content size.
How can I set size policy to grow-only policy?
for example, I set text to "12345" and QLabel should grow to minimal size to show this content, but when I set "12" this wouldnt shrink and stay old size.

Well, unless you don't need to use the space you want to recover for others widgets, you can use a QtGui.QSpacerItem; see QSpacerItem Class Reference.
You can set the size policy to the spacer item.
Note: This gets done automatically when you're using QtDesigner.
In QtDesigner, it should look like this:
The label has a cyan background for ilustrative purposes.
Here, you have some code sample:
Warning: the code has been written in Python. I don't know your lenguage preferences. But the interface is pretty much the same. Goog luck.
import PyQt4.QtGui as gui
import PyQt4.QtCore as core
import sys
if __name__ == "__main__":
app = gui.QApplication(sys.argv)
widget = gui.QWidget(None)
label = gui.QLabel(widget)
label.setStyleSheet("background-color: cyan;")
label.setMinimumWidth(10)
label.setText("Write some text above")
text = gui.QLineEdit(widget)
layout = gui.QVBoxLayout(widget)
hlayout = gui.QHBoxLayout(widget) # This layout will contains
# the label and a sacer item.
layout.addWidget(text)
hlayout.addWidget(label) # Add the label.
# Create the spacer.
spacerItem = gui.QSpacerItem(40, 20, gui.QSizePolicy.Expanding, gui.QSizePolicy.Minimum)
hlayout.addItem(spacerItem) # Add the spacer.
layout.addItem(hlayout)
# Slot for change the text of the label.
#core.pyqtSlot()
def on_textChanged():
label.setText(text.text())
text.textChanged.connect(on_textChanged)
widget.show()
sys.exit(app.exec_())

Related

Autodesk Maya model panel resize event

I'm writing a simple tool menu for Maya, and I'd like to stick it to the border of model panel (perspective).
from PySide import QtCore, QtGui
from maya import OpenMayaUI as omui
from shiboken import wrapInstance
class TestWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent = self.getMayaWindow())
self.setWindowFlags(QtCore.Qt.Tool | QtCore.Qt.FramelessWindowHint)
self.setFixedSize(100, 100)
panelPtr = omui.MQtUtil.findControl('modelPanel4')
panel = wrapInstance(long(panelPtr), QtGui.QWidget)
position = panel.mapToGlobal(panel.pos())
self.move(position.x(), position.y() + panel.geometry().height() / 2 - self.geometry().height() / 2)
mainLayout = QtGui.QVBoxLayout(self)
button = QtGui.QPushButton('CLOSE')
button.setFixedSize(80, 80)
button.clicked.connect(self.deleteLater)
mainLayout.addWidget(button)
def getMayaWindow(self):
omui.MQtUtil.mainWindow()
ptr = omui.MQtUtil.mainWindow()
return wrapInstance(long(ptr), QtGui.QWidget)
w = TestWidget()
w.show()
The main widget is positioned exactly where I want when it is created (horizontally on the left side of model panel, vertically - in the middle of model panel).
I need to reposition it accordingly when the model panel is resized, but model panel does not emit resized() signal. I'd appreciate any advise.
I've been trying many things to get this working yesterday. I did some additionnal researches today and came to this topic: cgsociety: Creating a floating button inside the viewport
In case of broken link, this is one of the answer:
You can use geometry but there are some issues with triggering
commands based on selection and the undo queue. If you want to go that
route, I would suggest looking into zooHud and zooTriggers (Part of
the zooToolbox)
If you are wanting actual GUI control parented to the viewport, mel
only offers hudslider, hudbutton, and headsUpMessage.
You can also use PyQt and parent in your own custom widgets/layouts or
whatever you want using something like this:
import maya.OpenMayaUI as apiUI import sip
from PyQt4 import QtGui
view = apiUI.M3dView()
apiUI.M3dView.getM3dViewFromModelPanel('modelPanel4', view)
viewWidget = sip.wrapinstance(long(view.widget()), QtCore.QObject)
global myBtn
myBtn = QtGui.QPushButton(viewWidget)
myBtn.setText('testing!')
myBtn.move(100, 100) #Relative to top-left corner of viewport myBtn.show()
You can do anything a full qt widget can do with that, so it's
extremely flexible. but it would require having PyQt installed, which
can be a barrier depending on your tools distribution.
I did a mix of this answer and your code:
from PySide import QtCore, QtGui
from maya import OpenMayaUI as omui
from shiboken import wrapInstance
class CustomQWidget(QtGui.QWidget):
def __init__(self, *args, **kwargs):
QtGui.QWidget.__init__(self, *args, **kwargs)
mainLayout = QtGui.QVBoxLayout(self)
closeButton = QtGui.QPushButton('CLOSE')
closeButton.setFixedSize(80, 40)
closeButton.clicked.connect(self.deleteLater)
helloButton = QtGui.QPushButton('HELLO')
helloButton.setFixedSize(80, 40)
helloButton.clicked.connect(self.printHello)
#Trying to fix glitchy background / Doesn't work, why?
#Is it because layouts don't have background?
p = self.palette()
p.setColor(self.backgroundRole(), QtCore.Qt.red)
self.setPalette(p)
self.setAttribute(QtCore.Qt.WA_StyledBackground, True)
##############################
mainLayout.addWidget(closeButton)
mainLayout.addWidget(helloButton)
def printHello(self):
print "Hello"
view = omui.M3dView()
omui.M3dView.getM3dViewFromModelPanel('modelPanel4', view) #Given the name of a model panel,
#get the M3dView used by that panel. If this fails, then a panel with the given name could not be located.
viewWidget = wrapInstance(long(view.widget()), QtGui.QWidget)
position = viewWidget.mapToGlobal(viewWidget.pos())
w = CustomQWidget(viewWidget)
w.move(0, viewWidget.geometry().height() / 2 - 100 / 2) #Relative to middle-left corner of viewport
w.show()
One of the issue I have it that the background of the widget is glitched:
If anyone knows why and how to fix it, I'll edit my answer with pleasure.
Else, when running this script from Maya's script editor, the widget follows the panel when it is resized.
I did fix such a problem, but not using Python/PyQt.
The problem itself is, that your Qt Widget is there. I have not found a way to make it not paint its background.
My solution was different: I derived from a Qt Layout, pushed all my widgets into that layout and used MQtUtil to get the QWidget of that modelPanel's modelEditor to attach the "real Qt layout" to it.
Heavy caveat that may make Python not suited: Maya doesn't expect "non-Maya" Layouts to be bound to "real-Maya" Widgets like modelEditors. So you need to listen to QEvents and find out when to destroy your layout, so Maya doesn't crash trying.
set autofillbackground True to fix your background painting issue

How can I set just `Widget` size?

How can I set just Widget size?
My code:
from PySide.QtGui import QApplication, QWidget, QLabel
import sys
app = QApplication(sys.argv)
mainWindow = QWidget()
gameWidget = QWidget(mainWindow)
#gameWidget.setGeometry(gameWidth, gameHeight) <-- I want to set size of gameWidget such like this. How can I do this.
gameWidget.move(100,0)
gameLabel = QLabel("This is game widget", gameWidget)
mainWindow.show()
Output:
Description:
This will create Window that contain Widget.
I want to set this Widget size. I know There is a method Widget.setGeometry, but it takes 4 parameter (x, y, width, height). I want a method like Widget.setGeometry which takes just size parameter (width, height).
P.S.
Feel free to modify my question. Because I'm always learning English!!
Thanks.
Just use QWidget.resize(weight, height).
For example:
gameLabel.resize(200, 100);
Besides, you can also use QWidget.sizeHint() to get a proper size automatically, for example:
gameLabel.resize(gameLabel.sizeHint());

QLabel doesn't redraw correctly when in a QHBoxLayout with a stretch

I'm having an odd problem with a label not being redrawn correctly when the text is changed, when it's inside a QHBoxLayout with an added stretch.
Consider the following (PyQt) example code:
from PyQt5.QtWidgets import QApplication, QHBoxLayout, QWidget, QLabel
from PyQt5.QtCore import QTimer
def clearlabel():
print("clearing")
lbl.setText("")
lbl2.setText("")
app = QApplication([])
# Widget 1: with stretch
w = QWidget()
w.move(0, 0)
w.resize(100, 20)
w.show()
lbl = QLabel()
lbl.setText("foo")
h = QHBoxLayout(w)
h.addStretch()
h.addWidget(lbl)
# Widget 2: without stretch
w2 = QWidget()
w2.move(0, 40)
w2.resize(100, 20)
w2.show()
lbl2 = QLabel()
lbl2.setText("foo")
h2 = QHBoxLayout(w2)
h2.addWidget(lbl2)
QTimer.singleShot(1000, clearlabel)
app.exec_()
Two widgets are shown, one with a QHBoxLayout with a stretch added, one without:
After 2 seconds, a timer sets both label texts from "foo" to an empty string. In the widget without stretch it works like expected - with the one with, however, the label text doesn't get redrawn:
What's going on there? Is this a Qt bug? Am I missing something?
What I found out so far:
This only seems to happen when setting an empty string, setting a shorter string works fine.
However in my real application, it happens without a stretch added as well.
I have now submitted this as QTBUG-36945.
Thanks to the helpful people in the #qt IRC channel (on Freenode), I figured out doing a repaint after setting the text works around the issue:
class Label(QLabel):
...
def setText(self, text):
super().setText(text)
if not text:
self.repaint()
Still I'd be glad to know if I'm just wrong somewhere, or if I should submit a Qt bug.

QListWidget adjust size to content

Is it possible to adjust QListWidget height and width to it's content?
sizeHint() always returns 256, 192 no matter what its content is.
QListWidgetItem's sizeHint() returns -1, -1, so I can not get content width.
Problem the same as here - http://www.qtcentre.org/threads/31787-QListWidget-width , but there is no solution.
import sys
from PyQt4.QtGui import *
class MainWindow(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
list = QListWidget()
list.addItem('111111111111111')
vbox = QVBoxLayout(self)
vbox.addWidget(list)
app = QApplication(sys.argv)
myapp = MainWindow()
myapp.show()
sys.exit(app.exec_())
sizeHint() always returns 256, 192 no
matter what its content is.
Thats because this is the size of the QListWidget, the viewport, not the items. sizeHintForColumn() will give you the max size over all items, so you can resize the widget like this:
list.setMinimumWidth(list.sizeHintForColumn(0))
If you don't want to force minimum width, then subclass and provide this as the size hint instead. E.g.:
class ListWidget(QListWidget):
def sizeHint(self):
s = QSize()
s.setHeight(super(ListWidget,self).sizeHint().height())
s.setWidth(self.sizeHintForColumn(0))
return s
Using takois answer I played around with the sizeHintForColumn or sizeHintForRow and found that you have to add slightly larger numbers, because there might be some style dependent margins still. ekhumoros comment then put me on the right track.
In short the full size of the list widget is:
list.sizeHintForColumn(0) + 2 * list.frameWidth()
list.sizeHintForRow(0) * list.count() + 2 * list.frameWidth())
According to the comment by Violet it may not work in Qt 5.
Also be aware that setting the size to the content, you don't need scrollbars, so I turn them off.
My full example for a QListWidget ajusted to its content size:
from PySide import QtGui, QtCore
app = QtGui.QApplication([])
window = QtGui.QWidget()
layout = QtGui.QVBoxLayout(window)
list = QtGui.QListWidget()
list.addItems(['Winnie Puh', 'Monday', 'Tuesday', 'Minnesota', 'Dracula Calista Flockhart Meningitis', 'Once', '123345', 'Fin'])
list.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
list.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
list.setFixedSize(list.sizeHintForColumn(0) + 2 * list.frameWidth(), list.sizeHintForRow(0) * list.count() + 2 * list.frameWidth())
layout.addWidget(list)
window.show()
app.exec_()
In order to effectively use sizeHint, you have to override it, at least in c++. In my experience, the default implementations for widgets can be pretty useless when you want a specific behavior. Attempts to force what you want with spacers or layouts end in disaster. If you can derive from QListWidget and override sizeHint, you can iterate through your items and find the longest string, then do some kind of magic to determine how wide it should be.
That's what I'd do, anyway.
First you should get your largest string in the list, that is easy to obtain.
After you get that string, do the following:
QFontMetrics * fm = new QFontMetrics(widget->font());
QRect rect;
rect = fm->boundingRect(string);
rect.width() has the width in pixels of the largest string
rect.height() has it's height.
Set the QListWidget width to that rect's width (plus the margins)
and it's height to that rect's height times the number of items
I didn't test the code, but hope it puts you on the right track
QListWidget *valList;
valList = new QListWidget(this);
valList->setSizePolicy (QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
valList->setMinimumSize (QSize(1111, 111));
You need to get the QHeaderView of your QListWidget and adjust its resize mode.
Read this documentation for more information
http://doc.qt.nokia.com/latest/qheaderview.html#ResizeMode-enum

qlistwidgetitem with custom widget doesn't look selected on the UI

I have a Qlistwidget in icon mode and I'm using setItemWidget to display my elements in my custom widgets, so far this is working.
Pretty much is like this one:
https://stackoverflow.com/questions/3639468/what-qt-widgets-to-use-for-read-only-scrollable-collapsible-icon-list
The only problem I have is that when I select the items, they don't look selected (no frame around them). They are being selected as I'm getting the right signals but you can't see the selection on the UI.
Any ideas on how to make them appear selected?
** Edit to add sample code **
(it is a modification on the code found on the previous link)
import sys
from PyQt4 import QtGui, QtCore
class displayItem(QtGui.QWidget): #A simple widget to display, just centers a digit in a 100x100 widget
def __init__(self,num):
QtGui.QWidget.__init__(self)
self.size=100
self.resize(self.size,self.size)
self.setMinimumSize(self.size,self.size)
self.text = num
def paintEvent(self,event):
p = QtGui.QPainter(self)
p.drawText(self.size//2,self.size//2,str(self.text))
app = QtGui.QApplication(sys.argv)
#Build the list widgets
list1 = QtGui.QListWidget() #This will contain your icon list
list1.setMovement(QtGui.QListView.Static) #otherwise the icons are draggable
list1.setResizeMode(QtGui.QListView.Adjust) #Redo layout every time we resize
list1.setViewMode(QtGui.QListView.IconMode) #Layout left-to-right, not top-to-bottom
listItem = QtGui.QListWidgetItem(list1)
listItem.setSizeHint(QtCore.QSize(100,100)) #Or else the widget items will overlap (irritating bug)
list1.setItemWidget(listItem,displayItem(1))
listItem = QtGui.QListWidgetItem(list1) #Add a few more items
listItem.setSizeHint(QtCore.QSize(100,100))
list1.setItemWidget(listItem,displayItem(2))
listItem = QtGui.QListWidgetItem(list1)
listItem.setSizeHint(QtCore.QSize(100,100))
list1.setItemWidget(listItem,displayItem(3))
list1.show() #kick off the app in standard PyQt4 fashion
sys.exit(app.exec_())
Thanks
/J
Yes. .
it is related to the viewMode.
When I set the viewMode for the list1 as ListMode, selected items look selected(highlighted)
list1.setViewMode(QtGui.QListView.ListMode)
still trying to figure out why it is not working with the iconMode. . .

Resources