I have a label that I want right aligned and the text to be right aligned. But when my code runs through and the label updates it, the StaticText aligns to the left of a button object. My code is below
hbox14 = wx.BoxSizer(wx.HORIZONTAL)
self.buttonRemove = wx.Button(self.panel,label='Remove')
self.buttonRemove.Bind(wx.EVT_BUTTON,self.removeAccount) # Remove account from list
self.labelSecTic = wx.StaticText(self.panel,label='0.0',style=wx.TE_RIGHT|wx.EXPAND)
self.labelSecTic.SetForegroundColour('white')
self.labelSecTic.SetBackgroundColour('black')
hbox14.Add(self.buttonRemove,proportion=0)
hbox14.Add(self.labelSecTic,proportion=1,flag=wx.ALIGN_RIGHT|wx.TE_RIGHT|wx.EXPAND)
When the label is updated I call
self.gui.labelSecTic.SetLabel(str(self.diff))
Any suggestions on how to make the labelSecTic stay fixed to the right side of the panel? Thanks.
First a side note: the style wx.TE_RIGHT is for wx.TextCtrl, it probably does nothing with the static text. About your real issue, you should force layout of the hbox14 sizer. Not sure what is the sizer/panel structure of your window, you should call Layout on some ancestor of hbox14, it might be self.gui.panel or even self.gui (don't know what gui is), so for example:
self.gui.labelSecTic.SetLabel(str(self.diff))
self.gui.Layout()
or
self.gui.labelSecTic.SetLabel(str(self.diff))
self.gui.panel.Layout()
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've found that if I make a wx.ScrollBar directly, I can modify its background color via the SetBackgroundColour() function. However, I'm unsure of how to reference to Scrollbar when it's part of a wx.ScrolledWindow.
How do I get reference to the Scrollbar in a ScrolledWindow?
A second question is this, is there a way to change more than just the Background color on a Scrollbar? I'm attempting to implement a "nighttime" mode, and thus want to mute all the colors a bit. Doing this in the rest of the program was fairly straight forward, but the scrollbars remain a problem.
You can get the reference to each ScrollBar (one horizontal and one vertical) by querying scrolledwindow.GetChildren() like:
sw = wx.ScrolledWindow(self)
for child in sw.GetChildren():
if isinstance(child, wx.ScrollBar):
print child
child.SetBackgroundColour(...)
Regarding your second question, there's SetForegroundColour(). You can always look through the documentation by doing:
python
>>> import wx
>>> help(wx.ScrollBar)
I'm trying to make a QScrollView with around 100 different labels and buttons.
But after I add them, the scrollbars do not appear.
here is an example of the code I wrote:
self.btn = {}
self.scroll = QScrollView(self)
self.scroll.setGeometry(QRect(0,0,300,300))
self.scroll.enableClipper(True)
vp = self.scroll.viewport()
for i in range(0,100):
self.btn[i] = QPushButton(vp)
for i in range(0,100):
self.scroll.addChild(self.btn[i],1,50*i)
self.scroll.setVScrollBarMode(QScrollView.AlwaysOn)
make the scrollbar appear but not to work.
The buttons get added to the QScrollView but I can't scroll down to see them all
what am I doing wrong? I'm using qt3.
You don't add all your little items to the scrollview. You have to insert a single, large container (a QFrame derived class, for example) into the scrollview that contains all your smaller widgets.
Actually you just need to give the scroll-view a layout and add your widgets to this. Adding them as sub-widgets of one big widget within the scrollview will do this for you, but it's messier.
I'm attempting to write a basic Tkinter GUI that has a Text widget at the top, then a Button widget left aligned under it, then another Text widget underneath the button. The problem I'm having is, after packing the Button widget to the left, when I then go to pack the second Text widget, it puts it next to the button on the right, rather than underneath the button. This happens regardless of what I set the side argument to for the second Text widget Here's a simple piece of code that demonstrates this behaviour:
from Tkinter import *
root = Tk()
w = Text(root)
w.pack()
x = Button(root, text="Hi there!")
x.pack(side=LEFT)
y = Text(root)
y.pack(side=BOTTOM)
root.mainloop()
So how would I go about setting up the second Text widget so that it appears below the button, rather than to the right of it?
There are generally two solutions to layout problems:
switch to using grid. It becomes real easy to do layouts like what you are trying to accomplish. Grid can solve probably 95% of all layout issues (it's amazing when you think about it -- Tk does with one manager what most toolkits need half a dozen to accomplish!)
use multiple frames. If some widgets need to be stacked top-to-bottom and some left-to-right you can't always get what you want packing everything in a single frame. Use one frame for the top-to-bottom parts of the layout and additional frames for the left-to-right content.
Also realize that widgets don't have to be children of the widget in which they are packed/gridded. You can use the "in" parameter to put widgets in some other container than their parent.
For example, in your specific example you can create three frames, top, middle, bottom. Pack these top-to-bottom in your toplevel window. Then you can pack the first text widget in the top, the button or buttons horizontally in the middle, and the other text widget in the bottom.
The advantage to such an approach is that it makes it much easier to change the layout in the future (which in my experience always happens at some point). You don't have to re-parent any of your widgets, just pack/place/grid them in some other container.
In your short example it doesn't make much difference, but for complex apps this strategy can be a life saver.
My best advice is this: layout isn't an afterthought. Do a little planning, maybe even spend five minutes drawing on some graph paper. First decide on the major regions of your app and use a frame or some other container for each (paned window, notebook, etc). Once you have those, do the same divide-and-conquer approach for each section. This lets you use different types of layout for different sections of your app. Toolbars get horizontal layout, forms might get vertical layout, etc.
I was initially misunderstanding how packing worked and didn't realise that the entire left side was being "claimed" when i did x.pack(side=LEFT). What I found after reading this and the answer by Alex here is that I was not really after having x packed to the left side at all, but rather having it anchored to the left, using anchor=W (W for West) instead of side=LEFT. My revised code snippet which does what I was after looks like this:
from tkinter import *
root = Tk()
w = Text(root)
w.pack()
x = Button(root, text="Hi there!")
x.pack(anchor=W)
y = Text(root)
y.pack(side=BOTTOM)
root.mainloop()
This way x is not "claiming" the left side anymore, it's just aligned to the left (or West) within its block of space.
Packing happens in the order the .pack methods are called, so once x has "claimed" the left side, that's it -- it will take up the left portion of its parent and everything else within its parent will be to its right. You need a Frame to "mediate", e.g....:
from Tkinter import *
root = Tk()
w = Button(root, text="Mysterious W")
w.pack()
f = Frame(root)
x = Button(f, text="Hi there!")
x.pack()
y = Button(f, text="I be Y")
y.pack(side=BOTTOM)
f.pack(side=LEFT)
root.mainloop()
(changed Texts to Buttons for more immediate visibility of layout only -- the Tkinter on this Mac doesn't show Texts clearly until they have focus, but Buttons are quite clear;-).
Do it the same way that WebView does using the Mosaic Canvas Widget Sets internals(which are very similar to Tk). The trick is that the second identical named Frame Object works as a Block Level Float(inline:block;) for everything placed after it and everything that calls "fr" already will automatically begin over inside of it.
You can have many doing this of TOP aligned widgets and simply add another identical named Frame where you want to break between side=LEFT's. Works after Bottom also.
fr=Frame(root)
fr.pack(fill=X, side=TOP)
block1=Label(fr)
block1.pack(side=LEFT)
block2=Label(fr)
block2.pack(side=LEFT)
block3=Button(fr)
block3.pack(side=LEFT)
# NAME IT THE SAME ID NAME AS THE FIRST MAIN FRAME...
fr=Frame(root)
fr.pack(fill=X, side=TOP)
# These NOW jump into the second Frame breaking the side=LEFT in new Frame
block4=Label(fr)
block4.pack(side=LEFT)
block5=Label(fr)
block5.pack(side=LEFT)
# AND THEY CONTINUE GOING side=LEFT AFTERWARDS.