How to hide all widgets in a QGridLayout() in python - 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.

Related

PyQt5: is there a signal when a QScrollBar visibility changes?

I am working in Maya with pyside2 (basically the same as PyQt5).
I have a gui with a scroll area in it... The scroll area has rows of some buttons and stuff that I want to expand horizontally if the user drags the window and expands it larger. Extra rows of these items can be added to it which makes the vertical scroll bar appear (obviously).
I'm trying to determine a way to prevent the slight resize of my rows of items when the scroll bar appears/disappears. Visually, I want the width of the items in each row to say the same if new rows get added and the scroll bar appears, or if the user expands the window some and the scroll bar disappears...
Is there a signal or something that gets sent if the scroll bar's visibility changes so I can adjust the margins of the layout for the items in the scroll area?
I know I can set the scroll bar to be visible or not, but I can't find anything that I can hook into for when this inherently changes as the size of the gui or contents in the scroll area is modified... If there's not already a signal, how could I go about creating one?
Ok, after searching around about the hideEvent like Aaron commented about, I've found something that seems to work...
I created an event filter for the vertical scroll bar in my scroll area... So, in the part of my code where the scroll area is defined, I have something like this:
scroll_area_widget = QtWidgets.QWidget()
self.scroll_area_layout = QtWidgets.QVBoxLayout()
scroll_area_widget.setLayout(self.scroll_area_layout)
scroll_area = QtWidgets.QScrollArea()
scroll_area.setWidget(scroll_area_widget)
self.scrollbar = scroll_area.verticalScrollBar()
self.scrollbar.installEventFilter(self)
Then, I define an 'eventFilter' method like this:
def eventFilter(self, o, e):
if o is self.scrollbar:
if e.type() == QtCore.QEvent.Show:
self.scroll_area_layout.setContentsMargins(5, 0, 3, 0)
elif e.type() == QtCore.QEvent.Hide:
self.scroll_area_layout.setContentsMargins(5, 0, 15, 0)
QtWidgets.QApplication.processEvents()
return False
I put the 'processEvents' in there because I'm getting a flickering when the scrollbar disappears where I think the widgets in the layout stretch out to fill the space before the contents margins gets updated... It doesn't help prevent the flickering every time, but it seems to be less than if I don't have it...
The question now is how do I avoid the flicker? Of course, another question is whether or not this is even a good way to solve this particular issue since I don't know enough about event filters... Is this something that will get triggered only when the scroll bar is shown/hidden, or does it apply to anything in the gui that gets shown/hidden? I ask that since the 'eventFilter' method doesn't seem specific to the scroll bar, and placing the if statement checking if it's the scrollbar seems like it might be a bit of overhead if every event in the whole gui is passing through....

Gtk how to add label item child

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.

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 to show a png image in Gtk3 with Python?

First of all, it is important to mention that I'm learning Python and Gtk+ 3, so I'm not an advanced programmer in these languages.
I'm trying to make a graphical interface in Gtk3 for a Python script that creates a png image, and I'd like to display it, but the PyGobject documentation is so scarce that I haven't found a way to do that. So far, my interface looks like this:
The buttons and text entries are arranged in a grid, and I'd like to keep empty the big space (represented by the big button) to the right until the script finishes building the image, and then show it in that area. The code is here.
Is there a way to do that using Python in Gtk3?
Thanks in advance,
Germán.
EDIT
Taking a look at the demos pointed out by #gpoo I discovered the Frame widget, and I implemented it in my GUI. This is how it looks like:
Inside the window class, I add the Frame to the grid:
self.frame_rgb = Gtk.Frame(label='RGB image')
self.frame_rgb.set_label_align(0.5, 0.5)
self.frame_rgb.set_shadow_type(Gtk.ShadowType.IN)
self.grid.attach_next_to(self.frame_rgb, self.label_img_name,
Gtk.PositionType.RIGHT, 3, 8)
I also connect the Run button to a callback function, so that when I click on it, my script creates and then displays the png image:
self.button_run = Gtk.Button(stock=Gtk.STOCK_EXECUTE)
self.button_run.connect('clicked', self.on_button_run_clicked)
self.grid.attach_next_to(self.button_run, self.entry_b_img,
Gtk.PositionType.BOTTOM, 1, 1)
Finally, my callback function is (no calculations yet, only render the image to the Frame for testing purposes):
def on_button_run_clicked(self, widget):
self.img = Gtk.Image.new_from_file('astro-tux.png')
self.frame_rgb.add(self.img)
but I got the following error when I click the Run button:
(makeRGB.py:2613): Gtk-WARNING **: Attempting to add a widget with
type GtkImage to a GtkFrame, but as a GtkBin subclass a GtkFrame can
only contain one widget at a time; it already contains a widget of
type GtkImage
Any help is appreciated!
You can use Gtk.Image. If you generate a file, you could use:
img = Gtk.Image.new_from_file('/path/to/my_file.png')
and add img to the container (GtkGrid in your case). Or, if you already have the Gtk.Image there, you can use:
img.set_from_file('/path/to/my_file.png')
Instead of ...from_file you can use from_pixbuf, and you can create a Gdk.Pixbuf from a stream.
In general, you can use the documentation for C and change the idiom to Python. Also, you can check the demos available in PyGObject, in particular, the demo for handling images.

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