So my application's main part consists of a QFrame which contains 2 other QFrames (left one for a menu, right for the content of the current page selected) I made the layout in QtDesigner as follows:
I added an animation for opening/closing the menu on the left, making the QPushButton texts visible when open, hiding them when closed (Only the icon shows in that case) by increasing the QFrame's width.
def ToggleMenu(self):
width = self.ui.frame_left_menu.width()
defaultWidth = 70
toggleWidth = 200
if width == defaultWidth:
toggleWidth = 200
self.ui.frame_content_right.lower()
self.ui.frame_left_menu.raise_()
else:
toggleWidth = 70
self.ui.frame_left_menu.lower()
self.ui.frame_content_right.raise_()
self.animation = QtCore.QPropertyAnimation(self.ui.frame_left_menu, b"minimumWidth")
self.animation.setDuration(300)
self.animation.setStartValue(width)
self.animation.setEndValue(toggleWidth)
self.animation.setEasingCurve(QtCore.QEasingCurve.InOutQuart)
self.animation.start()
ToggleMenu() is called when the user clicks on the menu button (thats outside of frame_center, increasing/decreasing its width.
When opening the menu, its width is increased, thus pushing the right QFrame along, making the available space smaller for actual content.
I would like to be able to make it so the menu is displayed above the content QFrame when opened. I tried calling raise_() and lower() on open/close, but that doesn't seem to change anything, I think that is because they are not overlapping to begin with, given the layout above.
I would like to avoid creating the layout at runtime if possible. How could I solve this?
Related
I have frames designed in seperate scripts that are all called to this central gui script which shows them using QMainWindow as one would expect.
However, I am trying to redesign the Main Window in such a way that there is a permanently fixed frame on the right hand side, and a tabbed frame on the left.
Before I attempted to make this happen, I could display, using setlayout, all of the frames on the mainwindow at once, however, when I try to add several of these"sub-widget" frames to my new tabbed frame everything gets annoying...
... effectively, I am taking already functioning widgets (designed w/ QFrame) called from other scripts and trying to make 2 new widgets with them (QTabWidget, for the left frame, and QGroupBox for the right). However, when run, the window pops up with my groupbox and tabwidgets completely empty, and my "sub-widgets" are displayed in new windows.
Here is a snippet:
tab_frame = QWidget()
tab_frame.layout = QVBoxLayout() #-------------------- Layout
tab_frame.layout.addWidget(self.FRAME_FROM_OTHER_SCRIPT)
tab_frame.layout.addStretch(1)
#### Tabs Parent ####
tabs = QTabWidget()
tabs.layout = QVBoxLayout()
tabs.addTab(tab_frame,"Tab 1")
#### Fixed Frame ####
vbox_az = QGroupBox()
vbox_az.layout = Qt.QVBoxLayout() #------------------------ Layout
vbox_az.layout.addWidget(self.FRAME_FROM_OTHER_SCRIPT)
self.main_grid = QGridLayout() #--------------------------- Layout
self.main_grid.addWidget(tabs,0,0,1,2)
self.main_grid.addWidget(vbox_az,0,2,1,3)
self.main_grid.setColumnStretch(2,1)
self.main_grid.setColumnStretch(5,1)
self.main_window.setLayout(self.main_grid)
I am unsure of what is actually happening... are widgets unable to be nested within other widgets?
Because setLayout relies on a layout input and not a widget I am unsure of how else to attack this problem other than by grouping my "sub-widgets" into groupboxes but I do not know why it's going so wrong.
Here is a picture screen-grab to illustrate further:
(for the sake of my question I have asked to split my window into two portions though I am actually splitting it three times)
I want to overlay two widgets in QtDesigner:
There is the big QTextBrowser, and below in the down right corner should be a non-interactiv label that I am going to use as a drag-grip to resize the window (the main widget is frameless so I need to implement it).
Usually this label will sit below the QTextBrowser, which leaves on the left of the grip-label a lot of unused space. So I want to put the grip-label above the QTextBrowser. I want to achieve this in QtDesigner. But the code would look like:
QHBoxLayout *layout = new QHBoxLayout(videoWidget);
QLabel *overlayWidget = new QLabel();
overlay->setAlignment(Qt::AlignCenter);
overlay->setText("Overlaid Text");
layout->addWidget(overlay);
Or as I already did in python:
self.textedit = QTextBrowser(self);
...
gripImage=QLabel(self.textedit);
There the part between the brackets is the parent widget.
That's how it looks right now, but this is not what I want:
This is usually simplest to achieve by using QGridLayout. It allows widgets to occupy the same grid cells. For this particular problem, a 1x1 grid is enough.
Steps to try it out with designer:
Create new form, plain Widget for simplicity
Add a text edit to it (drag and drop from Widget Box), and from Object Inspector you should see it becomes child of the root widget
Add a label to it (drag and drop from Widget Box), and from Object Inspector you should see it becomes child of the root widget
Right click on the root widget (easiest in the Object Inspector), and from the bottom of context menu, select Lay out > - Lay out in Grid
Right click on the label, and from Layout alignment > set it aligned to the corner you want
Done. Here's what it looks like in my Designer:
Now adapt above to your real form.
Ok, it appears achieving above with Designer is hard, and perhaps a bit a matter of luck of doing things just right... Designer just doesn't support doing what you want, it seems.
For clarity this is a complete source code:
QGridLayout *layout = new QGridLayout(widget);
QTextBrowser *textBrowser = new QTextBrowser();
QLabel *label = new QLabel();
label->setText("Overlaid Text");
//label gets positioned above textBrowser and is an overlay
layout->addWidget(textBrowser, 0, 0, Qt::AlignLeft | Qt::AlignTop);
layout->addWidget(label, 0, 0, Qt::AlignRight | Qt::AlignBottom);
I had the same problem but I did not manage to add Overlapping widgets in QtDesigner. Instead, I had to create the overlapping one dynamically after initializing my MainWindow.
I've got two widgets:
dataset_tableWidget (tableWidget)
spinner_dataset_tableWidget (QtWaitingSpinner)
and I wanted to make spinner_dataset_tableWidget spin over the dataset_tableWidget.
After initializing the MainWindow you can do:
#Crating QtWaitingSpinners dinamically and positioning it over the tableWidgets
dataset_tableWidget = QtWaitingSpinner(dataset_tableWidget)
dataset_tableWidget.setSizePolicy(dataset_tableWidget.sizePolicy())
I have 4 items in my canvas (canvas12). I'm trying to place the 2 drag buttons (frame1_drag/frame2_drag) in front of the windows (frame2can/frame1can). But I can't get tag_raise() or lift() to do anything. Right now the drag buttons are stuck behind the windows. And yes, it has to be this way because the drag buttons animate their respective framexcan window within canvas12.
frame2can = canvas12.create_window(0, 0, anchor='nw', width=sf(768), height=sf(fr1h),window=frame2)
frame1can = canvas12.create_window(0, sf(fr1h), anchor='nw', width=sf(768), height=sf(fr1h),window=frame1)
# Drag Buttons
frame1_drag = canvas12.create_rectangle(0, 0, sf(fr0h), sf(fr0h), outline="blue", fill="green", tags="token")
frame2_drag = canvas12.create_rectangle(0, sf(fr1h), sf(fr0h), sf(fr0h+fr1h), outline="blue", fill="green", tags="token")
canvas12.tag_raise(frame1_drag)
canvas12.tag_raise(frame2_drag)
You cannot place drawn items on top of window objects.
From the official tk documentation:
The items in a canvas are ordered for purposes of display, with the first item in the display list being displayed first, followed by the next item in the list, and so on. Items later in the display list obscure those that are earlier in the display list and are sometimes referred to as being “on top” of earlier items. When a new item is created it is placed at the end of the display list, on top of everything else. Widget commands may be used to re-arrange the order of the display list.
Window items are an exception to the above rules. The underlying window systems require them always to be drawn on top of other items. In addition, the stacking order of window items is not affected by any of the canvas widget commands; you must use the raise and lower Tk commands instead.
I would like to make an interactive module with ipywidgets.
So far so good but I'm stuck.
I want to hide the visibility of a certain ipywidget object dependent on a certain situation, and I want my printed text to show up above the widget and stay there.
dropdown=widgets.Dropdown(
options={'Coffee machine': 1, 'Washing machine': 2, 'Water Heater': 3, 'Heating System': 4, 'Dryer': 5, 'Oven': 6, 'Microwave': 7, 'Other':8},
value=1,
description='Apparaat:',
)
text_new=widgets.Text()
def text_field(value):
if(value==8):
display(text_new)
text_new.on_submit(handle_submit)
else:
text_new.visible(False) #Doesn't work but I want something like this
print("Today you had an increase in electricity consumption, would you like to name this device?") #This just be above the dropdown menu and be stuck
i=widgets.interactive(text_field, value=dropdown)
display(i)
What this does now:
When "Other" is checked in the dropdown menu, a text box appears where the user can type something.
However, when checking another machine, the text box stays there.
I just need a "hide" function but I can't seem to find one that works.
Also, after checking another option on the dropdown, the print dissapears, not coming back.
Had same problem so i found in
boton.layout.visibility = 'hidden'
or
check.layout.display = 'none'
they made some changes... i got if from here
Cannot create a widget whose initial state is visible=False
Given a widget:
import ipywidgets
button = ipywidgets.Button()
There are two direct ways to hide the the widget, with a notable difference.
Hide and unhide the widget without affecting overall page layout:
# Turn the widget "invisible" without affecting layout
button.layout.visibility = "hidden"
# Make the widget visible again, layout unaffected
button.layout.visibility = "visible"
Hide and unhide the widget and collapse the space that the widget took up:
# Hide widget and collapse empty space
button.layout.display = "none"
# Re-add the widget, adjusting page layout as necessary.
button.layout.display = "block"
When to use each one? As a rule of thumb, use layout.visibility so the page layout is not constantly jumping around as visibility is toggled. However, for very large widgets, consider using layout.display to avoid huge blank spaces.
For more general CSS information that applies here, see What is the difference between visibility:hidden and display:none?
In addition to the accepted answer, if you want to dynamically change the visibility of a control, you can declare the layout variable and reuse.
layout_hidden = widgets.Layout(visibility = 'hidden')
layout_visible = widgets.Layout(visibility = 'visible')
Like attach to an event:
def visible_txt(b):
text_box.layout = layout_visible
def hidden_txt(b):
text_box.layout = layout_hidden
btn_visible.on_click(visible_txt)
btn_hidden.on_click(hidden_txt)
I'm using a tkinter canvas and trying to make a chat box on the right side of my game. However, I found that when I do...
import turtle
import tkinter as tk
master = tk.Tk()
w = tk.Canvas(master,width=1155,height=600,cursor='cross_reverse', bg='#101010')
shift = 1.000
sc = turtle.TurtleScreen(w)
tu = turtle.RawTurtle(sc)
e = tk.Entry(master, bg = '#000', fg = '#03f', font = 'Courier', justify='right', insertbackground = '#101010',width='115')
lb = tk.Listbox(master,height=3)
#e.grid(row=3,column=3)
sc.bgcolor("#101010")
txt = tk.Text(master,state="disabled")
txt.pack()
lb.pack()
w.pack()
sc.tracer(100)
drawcontinents() #Draws stuff with turtle, works just fine
e.pack()
tk.mainloop()
... a few things go wrong.
1.Text and Entry do not seem to want to coexist. I seem to be only able to have one or the other. My plan was to use entry as a chat entry, and display messages in Text. My backup plan is to append messages to label.
2.Text, entry, and Label box take up the entire window in whatever rows they are in, which blocks out the rest of what I am trying to draw. In other words,it puts the text box in the center, with a big gray stripe from side to side across whatever I've drawn. Is there any way to just display the box, and put it to the right?
3.Whenever I try to use the grid system, my whole computer freezes and I have to restart. Is this because the program is taking up more space than I have available, or is this a known bug or problem with installation?
You cannot use both pack and grid at the same time for the same containing widget (ie: for all widgets inside the same frame, toplevel or root window).
What happens is this: grid lays out all the widgets, potentially changing the size of some widgets based on your options (ie: it may grow a widget to stick to the sides of the cell). pack then notices that some widgets changed size in the containing widget it thinks it is responsible for, so it redoes what it thinks is the proper layout. This may change the size of some widgets based on your options. grid then notices that some widgets it thinks it is responsible for change size so it redoes what it does, potentially changing the size of some widgets. pack notices and re-adjusts, grid notices and re-adjusts, pack notices, ... until the end of time.
The solution is simple: only use grid, or only use pack, for all widgets that have a common parent. In this case, all your widgets share the root window as their parent, so they all need to use grid, or they all need to use pack.