I have a senario where I have QComboBoxes (the black rectangles) and QPushButtons (the red cubes). I need the two buttons to always stay on either side of the most right combo.
.
Code example:
self.button1 QPushButton()
self.button2 = QPushButton()
def addCombo():
# remove buttons from next to previous right most combo
layout.removeWidget( self.button1 )
layout.removeWidget( self.button2 )
# add button left of new right most combo
layout.addWidget( self.button1 )
# add new right most combo
layout.addWidget( QComboBox() )
# add button right of new right most combo
layout.addWidget( self.button2 )
def removeCombo():
# remove buttons from next to previous right most combo
layout.removeWidget( self.button1 )
layout.removeWidget( self.button2 )
# delete right most combo
layout.takeAt( len(layout.children()) -1 )
# add button left of new right most combo # button , index
layout.insertWidget( self.button1 , len(layout.children()) - 2 )
# add button right of new right most combo
layout.addWidget( self.button2 )
#So for the first layout:
layout.addWidget( QComboBox() )
layout.addWidget( self.button1 )
layout.addWidget( QComboBox() )
layout.addWidget( self.button2 )
#second layout:
addCombo()
#third layout:
addCombo()
# fourth layout
Please let me know if you have any ideas, tips or solutions.
I think nested layouts will help you here. Instead of just adding your combo boxes to the main layout with the other buttons, add the combo boxes to their own layout and add that layout to the main layout. It should be easier to add and remove combo boxes from the inner layout leaving everything else where it is.
Related
I have a Tkinter Treeview with a header row. I am using the following style to style the header.
style = tk.ttk.Style()
style.theme_use('clam')
style.configure('Treeview.Heading', font=('Calibri', 10,'bold'))
style.map('Treeview', background=[('selected', 'blue')])
But I want the table to have just a title saying "INVOICES" and I do not want the separators in the header separating the columns, as seen in the photo below.
Is there a way to get rid of these separators?
Bonus points if you you can help me get the scrollbar to actually look like a scrollbar instead of being full (there are over 100 records in this test table).
Here is the rest of the code to place the treeview into a frame.
self.invoice_frame = tk.Frame(self, border=1, relief=tk.GROOVE, bg='white')
self.invoice_frame.place(relx=0.3, rely=row_3_top, relwidth=0.3425, relheight=0.3)
self.invoice_tree = tk.ttk.Treeview(self.invoice_frame, column=('c1', 'c2', 'c3'), show='headings')
self.invoice_tree.pack(side='left', fill='both', expand=True)
tree_scrollbar = tk.ttk.Scrollbar(self.invoice_frame, orient='vertical', command=self.invoice_tree.yview)
tree_scrollbar.pack(side='right', fill='y')
self.invoice_tree.column('c1', minwidth=40, width=100, anchor=tk.CENTER)
self.invoice_tree.heading('c1', text='')
self.invoice_tree.column('c2', minwidth=40, width=100, anchor=tk.CENTER)
self.invoice_tree.heading('c2', text='INVOICES')
self.invoice_tree.column('c3', minwidth=40, width=100, anchor=tk.CENTER)
self.invoice_tree.heading('c3', text='')
# adding random info
contacts = []
for n in range(1,100):
contacts.append((f'first {n}', f'last {n}', f'test{n}'))
for contact in contacts:
self.invoice_tree.insert('', tk.END, values=contact)
Thanks
You can set the relief style option to none to remove the separators.
style.configure('Treeview.Heading', font=('Calibri', 10,'bold'), relief='none')
For the scrollbar issue, you need to configure yscrollcommand option of the treeview:
self.invoice_tree.config(yscrollcommand=tree_scrollbar.set)
I have a grid of buttons in an 8x12 grid. Eventually, I want to be able to color a section (like a top left 3x3 grid) a specific color. For now, I have this question. Is it possible to get one button widget using button.bind("<Button-1>", myfunc2) and then get a second button widget using button.bind("<ButtonRelease-1>", myfunc2)? An outline of the code I have right now is below
class MyApp:
def __init__(self, main):
self.button_frame = tk.Frame(main)
tk.Grid.rowconfigure(root, 0, weight=1)
tk.Grid.columnconfigure(root, 0, weight=1)
self.button_frame.grid(row=0, column=0, sticky='nsew')
self.grid = tk.Frame(self.button_frame)
self.grid.grid(sticky='nsew', column=0, row=7, columnspan=2)
tk.Grid.rowconfigure(self.button_frame, 7, weight=1)
tk.Grid.columnconfigure(self.button_frame, 0, weight=1)
self.button_list = {}
self.createbuttongrid()
def createbuttongrid(self):
label = 1
for row in range(8):
for column in range(12):
button = tk.Button(self.button_frame, text='Well %s' % label)
button.bind("<Button-1>", self.buttonclick) # this line is in question
button.bind("<ButtonRelease-1>", self.buttonrelease) # along with this line
button.grid(row=row, column=column, sticky='nsew')
self.button_list[button] = (row, column)
label += 1
def buttonclick(self, event):
first_button = event.widget
print(self.button_list[first_button])
def buttonrelease(self, event):
second_button = event.widget
print(self.button_list[second_button])
if __name__ == "__main__":
import tkinter as tk
root = tk.Tk()
MyApp(main=root)
root.mainloop()
(The resizing (with the above example) doesn't work perfectly, but that's not important for now.)
Currently, when I run this and click on the top left button, I get (0, 0), and when I release I also get (0, 0). I think this is because the same widget is being passed into def buttonclick and def buttonrelease, but I'm not 100% sure
The <ButtonRelease> event will return the same widget that caught the <ButtonPress> event. That is due to the fact that clicking on a button causes the button to do a grab, which means all events are sent to the button rather than to any other button.
You can use the universal widget method winfo_containing to determine the widget at a given x/y coordinate. You must give it an x and y coordinate relative to the root window, which is conveniently supplied by the event object passed to an event handler.
def buttonrelease(event):
second_button = event.widget.winfo_containing(event.x_root, event.y_root)
...
here is a picture of what i want to be:
scrollbar
Actual code:
lb = Listbox(self.master, width=120, height=6)
scrollbar = Scrollbar(self.master, orient="vertical",command=lb.yview)
scrollbar.pack(side="right", fill="y")
lb.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=lb.yview)
lb.place(x=5,y=5)
Thanks!
You can create a new frame with listbox and scrollbar in it:
from tkinter import *
root = Tk()
root.geometry('500x300')
frame = Frame(root)
frame.place(x = 5, y = 5) # Position of where you would place your listbox
lb = Listbox(frame, width=70, height=6)
lb.pack(side = 'left',fill = 'y' )
scrollbar = Scrollbar(frame, orient="vertical",command=lb.yview)
scrollbar.pack(side="right", fill="y")
lb.config(yscrollcommand=scrollbar.set)
for i in range(10):
lb.insert(END, 'test'+str(i))
root.mainloop()
or since you're using place (which is not recommended), you can simply calculate the position of the scrollbar. grid would be the best layout manager in this case.
The problem is if you use only the 'place' positioning, the scrollbar doesn't appear.
The solution is to make two frames - one master frame with a widget scrollbar and
a second frame inside the master frame, where you can get the listbox. The frames can be positioned with place, the widget inside the frames with pack or grid.
Below is my source code, what works perfectly.
from tkinter import *
root = Tk()
root.geometry('500x300')
frame1 = Frame(root)
frame1.place(x = 10, y = 5,width=100,height=100) # Position of where you would place your listbox
frame1a=Frame(master=frame1)
frame1a.place(x=0,y=0,height=100,width=100)
lb = Listbox(frame1a, width=50, height=6)
lb.grid(row=0,column=0 )
scrollbar = Scrollbar(frame1, orient="vertical",command=lb.yview)
scrollbar.pack(side="right", fill="y")
lb.config(yscrollcommand=scrollbar.set)
for i in range(10):
lb.insert(END, 'test'+str(i))
root.mainloop()
I am working on a small texteditor in python. With app being my master i am trying to implement a textWidget, in which i want to place a functional scrollbar.
The problem i am facing is following:
In order to have a textWidget to place my scrollbar in, i have to implement my textWidget first. But already as an argument in Tk.Text i need to place the yscrollcommand for my scrollbar. Which means that my textWidget will not know what my scrollbar is.
If i turn it around i am not able to create my scrollbar within the textWidget, because it is not yet created.
First example where my textWidget is created first
# MENU BAR EXAMPLE
menu_bar = Tk.Menu()
# Set menu bar as menu for the app
app.config(menu=menu_bar)
# Fill menubar with "File" menu
filemenu = Tk.Menu(app,menu_bar, tearoff=0)
#filemenu.add_command(label="Exit", command=exit)
menu_bar.add_cascade(label="File", menu=filemenu)
menu_bar.add_cascade(label="File2", menu=filemenu)
filemenu.add_command(label="Exit", command=exit)
# BUTTON EXAMPLE
button = Tk.Button(app, text="Exit", command=quit)
button.pack(side=Tk.BOTTOM, fill=Tk.X)
# TEXT WIDGET
textWidget = Tk.Text(textWidget, yscrollcommand=scrollbar.set)
textWidget.pack(expand=True,fill=Tk.BOTH)
# SCROLLBAR
scrollbar=Tk.Scrollbar(textWidget)
scrollbar.pack(side=Tk.RIGHT, fill= Tk.Y)
scrollbar.config(command=textWidget.yview)
#Start the main event loop (i.e. run the tkinter program)
app.mainloop()
######################################################
Second example where scrollbar is created first
# MENU BAR EXAMPLE
menu_bar = Tk.Menu()
# Set menu bar as menu for the app
app.config(menu=menu_bar)
# Fill menubar with "File" menu
filemenu = Tk.Menu(app,menu_bar, tearoff=0)
#filemenu.add_command(label="Exit", command=exit)
menu_bar.add_cascade(label="File", menu=filemenu)
menu_bar.add_cascade(label="File2", menu=filemenu)
filemenu.add_command(label="Exit", command=exit)
# BUTTON EXAMPLE
button = Tk.Button(app, text="Exit", command=quit)
button.pack(side=Tk.BOTTOM, fill=Tk.X)
# SCROLLBAR
scrollbar=Tk.Scrollbar(textWidget)
scrollbar.pack(side=Tk.RIGHT, fill= Tk.Y)
scrollbar.config(command=textWidget.yview)
# TEXT WIDGET
textWidget = Tk.Text(textWidget, yscrollcommand=scrollbar.set)
textWidget.pack(expand=True,fill=Tk.BOTH)
And this is how i had to do to make it work. But it feelsBadMan if i have to create a textWidget, create a scrollbar and then create a textWidget again.
# MENU BAR EXAMPLE
menu_bar = Tk.Menu()
# Set menu bar as menu for the app
app.config(menu=menu_bar)
# Fill menubar with "File" menu
filemenu = Tk.Menu(app,menu_bar, tearoff=0)
#filemenu.add_command(label="Exit", command=exit)
menu_bar.add_cascade(label="File", menu=filemenu)
menu_bar.add_cascade(label="File2", menu=filemenu)
filemenu.add_command(label="Exit", command=exit)
# BUTTON EXAMPLE
button = Tk.Button(app, text="Exit", command=quit)
button.pack(side=Tk.BOTTOM, fill=Tk.X)
# TEXT WIDGET
textWidget = Tk.Text(app)
textWidget.pack(expand=True,fill=Tk.BOTH)
# SCROLLBAR
scrollbar=Tk.Scrollbar(textWidget)
scrollbar.pack(side=Tk.RIGHT, fill= Tk.Y)
textWidget = Tk.Text(textWidget, yscrollcommand=scrollbar.set) # <--- Creating textWidget again
#textWidget.pack(side=Tk.LEFT, fill=Tk.BOTH)
scrollbar.config(command=textWidget.yview)
textWidget.pack(expand=True,fill=Tk.BOTH)
# Start the main event loop (i.e. run the tkinter program)
app.mainloop()
Any ideas? =)
It takes three steps:
create the text widget
create the scrollbar, and link it to the text widget
link the text widget to the scrollbar
You can reverse the order if you want: create the scrollbar, then the text, then configure the scrollbar. Also, the scrollbar should not be placed inside the text widget. The text widget and the scrollbar typically share the same parent.
Example:
textWidget = Tk.Text(app)
scrollbar = Tk.Scrollbar(app, command=textWidget.yview)
textWidget.configure(yscrollcommand=scrollbar.set)
Is it possible to place a GtkMenuBar with other widgets together , instead of showing at the top of that window ?
Or i could use buttons , but when you hover your mouse over those buttons , the menu on the buttons won't just behave like a menu , which is , when you are close to one menu item , the menu pops down directly , without click , and other menu hide automatically. Can i make buttons like that ? Or other widgets that could have: label , image , and pop down menu item is cool.
Any ideas is appreciated.
Maybe the "enter-notify-event" and "leave-notify-event", connected to buttons, may help you do the thing, with for example, a popup menu show and hide respectively.
EDIT
I finally forgot those "enter" and "leave" events whose behaviour was a little complex, and just used the "motion-notify-event"...
Now I hope it is what you want !
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
class MenuExample:
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_size_request(200, 100)
self.window.set_title("GTK Menu Test")
self.window.connect("delete_event", lambda w,e: gtk.main_quit())
# A vbox to put a button in:
vbox = gtk.VBox(False, 0)
self.window.add(vbox)
vbox.show()
self.popped = False
# Create a button to simulate a menu
button = gtk.Button("press me")
vbox.pack_start(button, False, False, 2)
self.window.add_events(gtk.gdk.POINTER_MOTION_MASK)
self.window.connect("motion-notify-event", self.wakeup)
self.window.show_all()
self.bmenu = gtk.Button("A single entry menu")
self.bmenu.connect("clicked", self. menuitem_response, "Click on the magic menu !")
vbox.pack_start(self.bmenu, False, False, 2)
def wakeup(self, widget, event):
#print "Event number %d woke me up" % event.type
(x, y) = self.window.get_pointer()
if y < 30:
if self.popped == False:
self.popped = True
self.bmenu.show()
elif y > 60:
if self.popped == True:
self.popped = False
self.bmenu.hide()
# Print a string when a menu item is selected
def menuitem_response(self, widget, string):
print "%s" % string
def main():
gtk.main()
return 0
if __name__ == "__main__":
MenuExample()
main()