Tkinter Assign Different Functions To Each Ranged Button - python-3.x

the problem is its only works for one global function.. how to assign each button for a different function
from tkinter import*
class mainWindow:
def __init__(self,master):
mainFrame=Frame(master)
mainFrame.pack()
self.cv=Canvas(scrollregion=(0,0,200,1200),width=200,height=1200,bg='green')
self.scb=Scrollbar(command=self.cv.yview)
self.cv.pack(side=LEFT)
self.scb.pack(side=RIGHT,fill=Y)
self.cv.configure(yscrollcommand=self.scb.set)
#frame on canvas to pack title frame
self.cvFrame=Frame(self.cv)
self.cvFrame_window=self.cv.create_window(5,5,anchor=NW,window=self.cvFrame)
self.tFrame=Frame(self.cvFrame)
self.tFrame.pack(in_=self.cvFrame)
self.t=['Site Preparation','WBLFF','Frame','Roof Construction','Roof Finishes',]
self.tr=[0,1,2,3,4,5]
#range button created inside one frame
for i in range(5):
self.tButton=Button(self.tFrame,text=self.t[i],bg='purple',fg='white',width=20,relief=GROOVE)
self.tButton.grid(in_=self.tFrame,row=self.tr[i])
for i in range(0,1):
self.tButton.bind('<Button-1>',self.subT1)
#open up new subtitle under main title
def subT1(self,event):
self.s=['Site Preparation','Site Clearence','Earth Works']
self.sc=['dark violet','yellow','yellow']
self.sf=['white','black','black']
self.sr=[0,1,2]
self.sFrame=Frame(self.tFrame)
self.sFrame.grid(in_=self.tFrame,row=0)
for x in range(3):
self.sBtn=Button(self.sFrame,text=self.s[x],bg=self.sc[x],fg=self.sf[x],width=20,relief=GROOVE)
self.sBtn.grid(in_=self.sFrame,row=self.sr[x])
self.sBtn.bind('<Button-1>',self.destF)
#detroy frame back to main title
def destF(self,event):
self.sFrame.destroy()
#root window
root=Tk()
root.title('Built Up Rates')
root.geometry('220x600+0+0')
A=mainWindow(root)
root.mainloop()
Open Up The Program
Open up the subtitle by clicking the button
the problem is its only works for one global function.. how to assign each button for a different function

Firstly: you can use Button(command=function_name)
in place of bind('< Button-1 >',function_name)
Create list of functions
functions = [self.subT1, self.other_function]
for i in range(2):
Button(command=functions[i])
def subT1(self): # without `event` or with `event=None`

from tkinter import*
class mainWindow:
def __init__(self,master):
mainFrame=Frame(master)
mainFrame.pack()
self.cv=Canvas(scrollregion=(0,0,200,1200),width=200,height=1200,bg='green')
self.scb=Scrollbar(command=self.cv.yview)
self.cv.pack(side=LEFT)
self.scb.pack(side=RIGHT,fill=Y)
self.cv.configure(yscrollcommand=self.scb.set)
#Frame to Canvas
self.cvFrame=Frame(master)
self.cvFrame_window=self.cv.create_window(5,5,anchor=NW,window=self.cvFrame)
self.t=['Site Preparation','WBLFF','Frame','Roof Construction','Roof Finishes',]
self.tr=[0,1,2,3,4,5]
#range button created inside one frame
for i in range(5):
self.tButton=Button(self.cvFrame,text=self.t[i],bg='purple',fg='white',width=20,relief=GROOVE)
self.tButton.grid(in_=self.cvFrame,row=self.tr[i])
if i in range(0,1):
self.tButton.bind('<Button-1>',self.subT1)
if i in range(1,2):
self.tButton.bind('<Button-1>',self.subT2)
def subT1(self,event):
self.s=['Site Preparation','Site Clearence','Earth Works']
self.sc=['dark violet','yellow','yellow']
self.sf=['white','black','black']
self.sFrame=Frame(self.cvFrame)
self.sFrame.grid(in_=self.cvFrame,row=0)
for x in range(3):
self.sBtn=Button(self.sFrame,text=self.s[x],bg=self.sc[x],fg=self.sf[x],width=20,relief=GROOVE)
self.sBtn.grid(in_=self.sFrame,row=x)
self.sBtn.bind('<Button-1>',self.destF)
def subT2(self,event):
self.s=['WBLFF','Pile Cap','Column Stump','Ground Beam','Ground Slab']
self.sc=['dark violet','yellow','yellow','yellow','yellow']
self.sf=['white','black','black','black','black']
self.sFrame=Frame(self.cvFrame)
self.sFrame.grid(in_=self.cvFrame,row=1)
for x in range(5):
self.sBtn=Button(self.sFrame,text=self.s[x],bg=self.sc[x],fg=self.sf[x],width=20,relief=GROOVE)
self.sBtn.grid(in_=self.sFrame,row=x)
self.sBtn.bind('<Button-1>',self.destF)
#detroy frame back to main title
def destF(self,event):
self.sFrame.destroy()
#root window
root=Tk()
root.title('Built Up Rates')
root.geometry('220x600+0+0')
A=mainWindow(root)
root.mainloop()
got it :) by using 'if' statements... works well in ranged object and assign the parameters is there any other way to make it much more simpler like inheritance or global definition perhaps?

Related

Calling functions without closing the master window - Python Tkinter

I've tried to create a software. In this software there is a menu widget with function button that open functions e widgets. But, I've noticed, to keep going on script, it's necessary to close the master window (menu).
I've created an example to you understand my problem.
from tkinter import *
#Create Fuction that open new fuctions and widget
def test():
#Open a new widget
def fun_test_1():
top_level = Tk()
def test1():
top_level1 = Toplevel()
top_level1.title('new1')
top_level1.mainloop()
Button(top_level, text='test1',command=test1).pack()
top_level.mainloop()
fun_test_1()
#Before, open the second widget
def fun_test_2():
print('def fun_test_2(): works!')
top_level = Tk()
def test1():
top_level1 = Toplevel()
top_level1.title('new1')
top_level1.mainloop()
Button(top_level, text='Button', command=test1).pack()
top_level.mainloop()
fun_test_2()
root = Tk()
root.title('MASTER')
Button(root, text='Button',command=test).pack()
root.mainloop()
So, I need that fun_test_2() be called without close the root widget
And all functions i've tried to change Tk() to Toplevel() and Toplevel() to Tk().
The problem is you calling mainloop more than once, and for creating more than one instance of Tk. When you call mainloop, it won't return until that window has been destroyed. That's a fundamental aspect of how tkinter works.
The solution is to not create more than one instance of Tk and to not call mainloop more than once. If you need multiple windows, create instances of Toplevel. And again, only call mainloop once in total, not once per window.

How to open two modules in one window, Python Tkinter

I have a question: i am tossing the code from 2ch files, i have already lost ideas. Calling fileA.py opens a window for me with two buttons exit and start. Exit works but when I click start I need to open the second window fileB.pt. (I want both windows to open in one window) Seemingly works only problem I have is it doesn't open "window on window" but "docks underneath" and I have the effect of two windows open :/. Please help, thank you in advance:) Python 3.10
fileA.py
import tkinter as tk
from GUI.module.scale_of_img import get_scale
class FirstPage:
def __init__(self, root):
self.root = root
def get_settings(self):
# Window settings
self.root.title('....')
self.root.resizable(False, False)
self.root.geometry("1038x900")
if __name__ == '__main__':
first = FirstPage(tk.Tk())
first.get_run_first_page()
fileB.py
import tkinter as tk
"importy..."
''' The second side of the application '''
class SecondPage:
def __init__(self, root=None):
self.root = root
self.my_canvas = tk.Canvas(self.root, width=1038, height=678)
self.my_canvas.pack(fill="both", expand=True)
if __name__ == '__main__':
second = SecondPage(tk.Tk())
second.get_run()
in order to put two "windows" in the same "window" you need to put all items inside a Frame, which is basically a container than you can simply pack when you want everything to show and unpack when you want everything in it to disapear.
all items in the first window will be children of a frame and all items in the second window will be children of another frame, and to switch you just need to call pack_forget() on one and pack() on another.
for the first file
class FirstPage:
def __init__(self, root):
self.root = root
self.frame = tk.Frame(root)
self.frame.pack(expand=True)
def get_picture(self):
# all items inside this window must be children of self.frame
self.my_canvas = tk.Canvas(self.frame, width=1038, height=500)
...
def get_second_page(self):
from GUI.module.second_page import SecondPage
self.frame.pack_forget() # to hide first page
# self.frame.destroy() # if you are never brining it back
SecondPage(self.root).get_run()
and for the second file
class SecondPage:
def __init__(self, root=None):
self.root = root
self.frame = tk.Frame(root) # new frame
self.frame.pack(expand=True)
self.my_canvas = tk.Canvas(self.frame, width=1038, height=678)
self.my_canvas.pack(fill="both", expand=True)
def get_button(self):
# Add buttons
# all here should be children of self.frame now
button1 = tk.Button(self.frame, text="...", )
...
you could destroy the first frame when you switch over to save some resources if you don't intend to return to it ever again, but the difference in memory is negligible.
assuming what you want is another Tk window to open, you shouldn't give it the same root, instead use an instance of Toplevel
from tkinter import Toplevel
# class definition here
def get_second_page(self):
from GUI.module.second_page import SecondPage
SecondPage(Toplevel(self.root)).get_run()
passing the Toplevel as a child of self.root is necessary, but note that the two windows have different roots.
Edit: turns out this wasn't what the OP ment by "window on window" -_-, but it am keeping it here for other readers.

Scrollbar on top of listbox issue

I'm trying to attach a scrollbar element to the side of the listbox element.
When I try to put scrollbar to the side of the listbox, the scrollbar jumps to top of the listbox. I tried to grid it and pack it. None of them seems to work.
It looks like this:
The code:
from tkinter import *
class MyApp(Frame):
def __init__(self, root):
root.title('My app')
super().__init__(root)
self.grid()
self.createWindow()
def createWindow(self):
self.listbox = Listbox(self)
self.listbox.grid(row=0, column=0)
self.scrollbar = Scrollbar(self.listbox)
self.scrollbar.grid(row=0, column=1)
if __name__ == '__main__':
ma = MyApp(Tk())
mainloop()
The thing that I was trying to accomplish can't be done in Tkinter. I tried to use Wx module and it works great.

Python Tkinter Check if Frame exists

I am trying to do the following:
Create a Tkinter App with a 'File' menu.
The File Menu has 2 options, Add and View.
The Add option adds a Frame and then adds a Label widget (Label 1) in the frame.
If I then select the View option form the file menu, it should print out whether or not a Frame widget already exists.
Following is my attempt at it, but I receive the error
AttributeError: 'Test' object has no attribute 'tk'
when I select the View option, can someone please help point out what I am missing here?
from tkinter import Tk, Menu, Label, Frame
class Test():
def __init__(self):
self.gui = Tk()
self.gui.geometry("600x400")
menu = Menu(self.gui)
new_item1 = Menu(menu)
menu.add_cascade(label='File', menu=new_item1)
new_item1.add_command(label='Add', command=self.addlbl)
new_item1.add_command(label='View', command=self.viewlbl)
self.gui.config(menu=menu)
self.gui.mainloop()
def addlbl(self):
f=Frame()
f.pack()
lbl1 = Label(f, text="Label 1").grid(row=0, column=0)
def viewlbl(self):
print(Frame.winfo_exists(self))
T=Test()
I replicated your problem. I got the code below to work using Python3.4 on Linux. f needs to become self.f. I named it self.frame. This enables the frame to be accessed outside of the method it is created in.
from tkinter import Tk, Menu, Label, Frame
class Test():
def __init__(self):
self.gui = Tk()
self.gui.geometry("600x400")
menu = Menu(self.gui)
new_item1 = Menu(menu)
menu.add_cascade(label='File', menu=new_item1)
new_item1.add_command(label='Add', command=self.addlbl)
new_item1.add_command(label='View', command=self.viewlbl)
self.gui.config(menu=menu)
self.gui.mainloop()
def addlbl(self):
self.frame = Frame(self.gui)
self.frame.pack()
lbl1 = Label(self.frame, text="Label 1")
lbl1.grid(row=0, column=0)
def viewlbl(self):
print('frame exists {}'.format(self.frame.winfo_exists()))
T=Test()

Overriding QLabel widget in PyQT

I am new to PyQt perhaps thats why facing this issue. I am trying to make a component inserter for excel sheets. For this purpose I am using QT for interface and using Qlabels within parent class of QMainWindow. On the basis of item selected from Qlist Widget, few Qlabels have to change on mainwindow dynamically Component inserter
As can be seen in above picture, the labels like WCAP-; Part Number and all below needs to change dynamically when the selected items change(when select button is clicked). But what happening is if I choose a different item from list, the previous Label stays and the new label is overlapping it as can be seen from picture below showing overlapping of labels
The code below shows that whenever button "Select" is pressed", label2 (Qlabel2) is formed, how can i delete the previous label whenever select button is pressed so that new Label dynamically replaces the old label.
Thanks a lot in advance.
def Display(self):
self.close()
label1 = QtGui.QLabel("Select the sheet",self)
label1.move(0,15)
self.listwidget = QtGui.QListWidget(self)
self.listwidget.move(0,40)
self.listwidget.resize(150,150)
for i in range(len(self.sheetnames)):
self.listwidget.addItem("%s"%self.sheetnames[i])
btn = QtGui.QPushButton('Select',self)
btn.resize(50,50)
btn.move(170,40)
btn.clicked.connect(self.Selected)
self.show()
def Selected(self):
self.close()
selecteditem = self.listwidget.currentItem().text()
self.sheetindex = self.sheetnames.index(selecteditem)
print self.sheetindex
aa = self.loadsheet.sheet_by_name(selecteditem)
global label2
label2 = QtGui.QLabel("",self)
label2.setText(selecteditem)
label2.move(0,190)
self.show()
self.InputParameters(aa)
You see a new QLabel because you create a new one every time you call Selected. I would initiate the UI at the creation of the widget (in the __init__ method):
def __init__(self):
self.label2 = QtGui.QLabel("",self)
And only update the text of the Qlabel when Selected is executed:
def Selected(self):
self.label2.setText(selecteditem)
About reinitializing all labels with an unknown number of labels and removing the old ones, you might want to look at QLabel.setParent(None). I wrote you a little example:
from PyQt4 import QtGui, QtCore
import sys
class test(QtGui.QWidget):
def __init__(self,parent=None):
self.widget=QtGui.QWidget.__init__(self, parent)
# Button to add labels
self.btnAdd = QtGui.QPushButton('Add')
self.btnAdd.connect(self.btnAdd, QtCore.SIGNAL('clicked()'),self.btnAddPressed)
# Button to remove labels
self.btnRemove = QtGui.QPushButton('Remove')
self.btnRemove.connect(self.btnRemove, QtCore.SIGNAL('clicked()'), self.btnRemovePressed)
# List to keep track of labels
self.labels=[]
# Layout
self.hbox = QtGui.QHBoxLayout()
self.hbox.addWidget(self.btnAdd)
self.hbox.addWidget(self.btnRemove)
self.setLayout(self.hbox)
self.show()
def btnAddPressed(self):
"""Adds a new label."""
self.labels.append(QtGui.QLabel("lbl"+str(len(self.labels)+1), self))
self.hbox.addWidget(self.labels[-1])
def btnRemovePressed(self):
"""Removes last label."""
self.labels[-1].setParent(None)
self.labels.pop(-1)
def main():
#Creating application
app = QtGui.QApplication(sys.argv)
main_win = test()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Resources