Gtk how to add label item child - python

As a way how to learn Gtk and python I decided to re-write program which GUI was build in Glade (Gtk 2). I need a little push now, as I don't know how to make Hbox child item of Label ? Or maybe I just misunderstood it ? Here's how it looks in Glade:
how to add Hbox into this piece of code ? :
table1.attach(frame, 0, 2, 0, 1, gtk.FILL, gtk.FILL)
notebook1.append_page(table1, label1)
align = gtk.Alignment(0.5, 0.5, 1, 1)
frame.add(align)

You can't really create the structure shown in the Glade screenshot: You can only add one child to a GtkFrame. I believe Glade is mistakenly showing you an internal child of the frame (the GtkAlignment that the frame itself uses to layout the possible frame label).
Don't add the GtkAlignment at all (use the GtkFrame API instead if you need to set the frame label alignment). Just create an HBox and add it into the Frame, then create a Label and pack it into the HBox.

Related

WxPython, Collapsible Pane containing Scrolled Window

I'm trying to create a Collapsible Pane, that is also scrollable, for when the contained button-list is larger than the screen. So I put a ScrolledWindow inside the Pane - and got this error:
Gtk-WARNING: Attempting to add a widget with type GtkScrolledWindow to a GtkExpander, but as a GtkBin subclass a GtkExpander can only contain one widget at a time; it already contains a widget of type wxPizza
What, they don't like Pizza? :) My first reading of that, makes me think they are incompatible widgets, as both are presumably of type GtkExpander. But this question - Scrollbars not showing - appears to use both widget-types. With some differences - first, they're putting the CollapsiblePane inside the ScrolledWindow, and second, it's actually a PyCollapsiblePane, from the AGW library of WxPython.
So is it possible, with some combination of widgets, to have a collapsible object, that when expanded, contains a scrolling list of objects? And if so, how? Or are the two widgets just incompatible (in that order)?
Found the problem. Turns out that a Collapsible-Pane has an inner-panel that is intended to be used for children.
class BadCollapsingPanel(wx.CollapsiblePane):
def __init__(self, parent):
super().__init__(parent, wx.ID_ANY, style=wx.SUNKEN_BORDER)
self.parent = parent
self.inner_pane = self.GetPane()
self.inner_pane.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
# self.very_bad_panel = ScrollingPanel(self) # Breaks
self.very_bad_panel = ScrollingPanel(self.inner_pane) # Works

Show scrollbar in QTreeWidget with respect to the custom item widgets' size

I am using PyQt5 for my application and a QTreeWidget to display content. Since I need to display rich text (HTML) each item has its text property set to "" and I create individual QLabels with the desired text. I then use QTreeWidget.setItemWidget. My problem is that using that method, when the QTreeWidget is smaller (in width) than the items' width, the horizontal scrollbar is not displayed. Which is logical, since from the point of view of the QTreeWidget, each item has width 0 because its text is empty.
I tried using a custom helper method that I use instead of the QLabel.setText method by automatically calling QLabel.setFixedSize method afterwards, but it doesn't work very well (the size is off by 5 to 90 pixels each time).
How would it be possible to make the whole thing determine automatically when to show the scrollbar, and what width to use for them?
MCVE:
tree = QTreeWidget()
item = QTreeWidgetItem(tree)
label = QLabel()
label.setText("<b>some text here</b>")
tree.setItemWidget(item, 0, label)
I even struggled with the same problem and finally this solution works for me:
Set the treewidget header StretchLastSection to False
treeWidget.header()->setSectionResizeMode(column, QtWidgets.QHeaderView.ResizeToContents)

How to hide all widgets in a QGridLayout() in python

I'm currently looking for a smart way to start a game made in PyCharm by using the PyQt library and I wanted to try and hide several widgets, or complete Layouts but the function .hide() doesn't work on complete layouts.
Is there a code to hide layouts completely or is hiding all the widget in that box the way to go?
If the answer is the latter, how can I make it easier for me than to go through every single widget and add the .hide() extension to them. Can I collect all those widgets in some sort of parent and then just parent.hide() as well as parent.show() ?
The code looks like this atm:
playerbox = QGridLayout()
playerbox.addWidget(self.player1, 0, 0)
playerbox.addWidget(self.player2, 0, 1)
playerbox.addWidget(self.stake, 1, 0)
playerbox.addWidget(self.money, 1, 1)
playerbox.addWidget(betButton, 2, 0)
playerbox.addWidget(foldButton, 2, 1)
playerbox.addWidget(bettingtext,3,0)
And the playerbox is supposed to be a box in a game that displays several items. I just want this box not to show anything before the game has started (this is done when the user press start but this has already been dealt with).
Thanks in advance!
I like this one:
[playerbox.itemAt(i).widget().hide() for i in
range(playerbox.rowCount()*playerbox.columnCount()) if
playerbox.itemAt(i)]
the if clause is required since you could have empty spots in your grid, and then itemAt() returns None.

Maya Outliner in Pyqt doesn't charge

Well I'm trying to use a outliner in maya with Pyqt4 and python, My outliner is in a Qsplitter with other two panels, it seems the code is ok, but when I run the code sometimes the Outliner appears, sometimes doesn't appear
this is the code where I create the Outliner:
self.outliner = QWidget()
self.outliner.setObjectName("outliner")
self.outLayout = QGridLayout()
self.outLayout.setContentsMargins(0, 0, 0, 0)
self.outLayout.setObjectName("outLayout")
self.outliner.setLayout(self.outLayout)
outL = cmds.outlinerPanel(mbv=False, p="outLayout")
cmds.control(out, edit=True, visible=True, parent="outLayout")
And this is how I display it:
self.splitter1 = QSplitter()
self.splitter1.addWidget(self.list)
self.splitter1.addWidget(self.outliner)
What I need to modify to make it work every time
EDIT:
I Upgraded my code, deleting inecesaring lines, but still doesn't work the way i need
Switching to answer format:
The current code would be better if you were not dependent on the hard coded names:
self.outliner.setLayout(self.outLayout)
#snip#
# in ordinary maya / python usage you'd do this....
panelLayout = cmds.formLayout("panelLayout", parent=self.outLayout)
# but in your original sample self.Outlayout is not a maya widget but a QT one
# so it doesn't resolve down to a string...
# the line below is the usual idiom
outliner = cmds.outlinerPanel("out", mbv=False, p=panelLayout)
that way the real names of the controls will be used and you're less vulnerable to strays with the same name. It's still good practice to delete strays - but it's hard to be sure without making the code very cumbersome.
Also, the line:
cmds.control(out, edit=True, visible=True, parent="panelLayout")
looks redundant - is it intentional? Is it a lefttover of an attempt to parent the outline? because the p= keyword ought to be doing your parenting for you.
Lurker update
As OP pointed out, code above wont' work - i've updated the sample to indicate the problem for the benefit of future readers.
well this is what i finished doing:
The first part is the same
self.outliner = QWidget()
self.outliner.setObjectName("outliner")
self.outLayout = QGridLayout()
self.outLayout.setContentsMargins(0, 0, 0, 0)
self.outLayout.setObjectName("outLayout")
self.outliner.setLayout(self.outLayout)
then I "translate" Pyqt to maya to be able to assign the layout with any extra code
panel = mui.MQtUtil.fullName(long(sip.unwrapinstance(self.outLayout)))
cmds.setParent(panel)
if cmds.modelPanel("outL", exists=True):
cmds.deleteUI("outL")
outL = cmds.outlinerPanel(mbv=False)
cmds.control(outL, edit=True, visible=True, p=panel)
ptr = mui.MQtUtil.findControl(outL)
Transform a Maya widget to a QWidget
self.outPanel = sip.wrapinstance(long(ptr), QObject)
And Finally add the Widget to my Layout
self.outLayout.addWidget(self.outPanel)

How do you create a LabelFrame with a scrollbar in Tkinter?

I'm using Python and Tkinter to create a GUI for a program I'm writing, and I'm having a couple of problems.
I have three objects descended from LabelFrame in an object descended from Frame. One of the LabelFrame descendants is two columns of corresponding Label and Entry objects.
The problem is that there are a varying number of Label and Entry pairs, and there can be more than fit on the screen. I need a way to make a scrollbar for this LabelFrame so that everything fits on the screen. I've tried various ways of making a Scrollbar object, but nothing seems to work. How can I bind a scrollbar to this frame?
Also, I need to be able to refresh or reload this LabelFrame when the load_message() method is called, but it just redisplays the new pairs on top of the old ones (so when there are less pairs in the new set, the old set is still visible at the bottom). I've tried using grid_forget() but either nothing changes or the whole frame doesn't display. How can I forget this display and then redisplay it?
Here is the code for this class:
class freq_frame(LabelFrame):
def __init__(self, master = None, text = 'Substitutions'):
LabelFrame.__init__(self, master, text = text)
self.grid()
def load_message(self):
self.frequency = get_freq(message)
self.create_widgets()
def create_widgets(self):
self.label_list = [Label(self, text = get_label(char, self.frequency[char]), justify = LEFT) for char in self.frequency.keys()]
self.entry_list = [Entry(self, width = 1) for char in self.frequency.keys()]
for n in range(len(self.label_list)):
self.label_list[n].grid(column = 0, row = n)
for n in range(len(self.entry_list)):
self.entry_list[n].grid(column = 1, row = n)
If anyone can help with either of these problems, I'd appreciate it.
Also, this question seems like it might be a little thin, but I don't know what to add. Don't hesitate to ask for more information (but be specific).
Thanks!
Labelframes don't support scrolling. So the short answer to your question is "you can't". It sounds obvious, but if the documentation for a widget doesn't say it supports scrolling, it doesn't support scrolling.
However, there is a simple solution. First, add a canvas as a child to the labelframe and pack it so that it fills the labelframe. Attach scrollbars to the canvas and add them to the labelframe too. Then embed a frame within the canvas, add your widgets to that inner frame, and then adjust the scrollregion of the canvas to match the size of the frame after you've added all the inner labels and entries.
It sounds complicated, but it's really very straight-forward.
As for re-creating the widgets when you call load_message, calling grid_forget only removes them from view, it doesn't actually destroy the widgets. Over time you could potentially end up with hundreds of non-visible widgets which is almost certainly not what you want.
Instead, you want to first destroy all the existing widgets. That's pretty easy if they all are in the same parent, since you can ask the parent for a list of all its children. Just iterate over that list to delete each child, then add any new children. An even easier solution is to destroy and recreate that inner frame that contains the labels and entries. When you delete a widget, all child widgets get automatically destroyed. So, delete that inner frame, create a new one, and add your labels and entries again.

Categories