I created a generatable charts that saved in postgresql. And I added some buttons like a delete button for every charts. It look like this
How can I use the delete button? I tried to create another callback, but I think it didn't read every button. If I click the other delete button it's printing "None" but, if I click the last one it's printing "1". Is there another solution? I wanted to use the delete button for every chart. I want to get the value from the dcc.input if I click the button. I'm open with any suggestion to improve my work.
app.layout = html.Div(id='graphs', children=[
])
#app.callback(Output('graphs', 'children'),
Input('graphs', 'children'))
def update_extend_traces_traceselect(child):
fig = go.Figure()
fig.add_trace(
go.Bar(
x=xval,
y=yval,
name=barname,
marker_color=barcolor,
orientation=orientation,
marker_line_color=markerlinecolor,
marker_line_width=float(markerlinewidth)
))
fig.update_layout(
title=title,
)
child.append(html.Div(
dcc.Input(
id="charts-id",
type="text",
value=chart_ID[i]
),
html.Button('Delete', id='delete-chart', n_clicks=0),
dcc.Graph(figure=fig,
config={
'displayModeBar': False,
})],
style={'height': '550px', 'width': '550px', 'margin': '10px',
'border': '1px solid'}))
return child
#app.callback(Output('delete-chart', 'n_clicks'),
Input('delete-chart', 'n_clicks'),
State('charts-id', 'value')
)
def delete(n_clicks, value):
print(n_clicks) //only for the last chart works//
print(value) //printing the value of the last dcc.input//
if "OverviewChart" == '__main__':
app.run_server(debug=True)
Related
I have a Tkinter GUI with a main menubar, using Tkinter's Menu widget. I want to execute code prior to posting a submenu (another Menu item cascaded from it via .add_cascade()), so that I can dynamically change its contents before it's shown. I have this working using Menu's postcommand argument, but I noticed a huge inefficiency using that; the postcommand callback for all submenus are called when clicking on any one submenu, not just the specific submenu that was created to have the callback. Even clicking on the menu bar where there are no menu items also executes all callbacks, even though no submenus are created.
Is this expected behavior from the Menu module and its postcommand argument? I don't understand why this still happens after creating separate Menu instances for the dropdowns.
I've tried hooking into Tk.Menu's native methods, but none of them are called when simply clicking on the menubar items to bring up a cascaded Menu. And even though .add_cascade() accepts a 'command' argument, it only calls the callable provided by that if .add_cascade()'s 'menu' argument is not included or if it's a lambda expression (both of which result in no submenu being displayed when you click on the item). (You can see this using the test() function, below.)
Here's a simple app showing this behavior:
import Tkinter as Tk
import time
def test(): print 'test'
class firstMenu( Tk.Menu ):
def __init__( self, parent, tearoff=False ):
Tk.Menu.__init__( self, parent, tearoff=tearoff, postcommand=self.repopulate )
def repopulate( self ):
print 'repopulating firstMenu'
time.sleep( 2 ) # Represents some thinking/processing
# Clear all current population
self.delete( 0, 'last' )
# Add the new menu items
self.add_command( label='Option 1.1' )
self.add_command( label='Option 1.2' )
class secondMenu( Tk.Menu ):
def __init__( self, parent, tearoff=False ):
Tk.Menu.__init__( self, parent, tearoff=tearoff, postcommand=self.repopulate )
def repopulate( self ):
print 'repopulating secondMenu'
time.sleep( 2 ) # Represents some thinking/processing
# Clear all current population
self.delete( 0, 'last' )
# Add the new menu items
self.add_command( label='Option 2.1' )
self.add_command( label='Option 2.2' )
class Gui( object ):
def __init__( self ): # Create the TopLevel window
root = Tk.Tk()
root.withdraw() # Keep the GUI minimized until it is fully generated
root.title( 'Menu Test' )
# Create the GUI's main program menus
menubar = Tk.Menu( root )
menubar.add_cascade( label='File', menu=firstMenu( menubar ), command=test )
menubar.add_cascade( label='Settings', menu=secondMenu( menubar ) )
root.config( menu=menubar )
root.deiconify() # Brings the GUI to the foreground now that rendering is complete
# Start the GUI's mainloop
root.mainloop()
root.quit()
if __name__ == '__main__': Gui()
If you click on anywhere on the menubar, BOTH postcommand callbacks are called. I need (and would expect) only one of them to be called when you click on the respective Menu item.
I'm not sure if it's relevant, but I also use the same menu items as context-menus over another widget. So their .post() method also needs to be able to trigger the same callback before the menu is displayed.
Thanks in advance if you have any insight.
This was a really tricky problem, but I finally found a solution. After a lot of searching, numerous failed experiments, and more searching, I came across the virtual event <<MenuSelect>> and this pivotal line of code: print tk.call(event.widget, "index", "active"), pointed out by Michael O' Donnell, here.
The first weird part about trying to use this, is that event.widget isn't an instance of a widget object in this case, it's a tcl/tk path name string, e.g. '.#37759048L'. (This seems to be a bug in Tkinter, as even other virtual events I've tested -TreeviewSelect and NotebookTabChanged- include actual widget instances, as expected.) Regardless, the tcl/tk string can be used by the print tk.call(event.widget, "index", "active") command; that returns the index of the currently active menu item, which is huge.
The second issue that comes up with using the MenuSelect event is that it's called multiple times when traversing the menus normally. Clicking on a menu item calls it twice, and moving the mouse to a neighboring menu item, or moving the mouse to a submenu and then back to the main menu item, will also call it twice. Leaving the menu can as well. But this can be cleaned up nicely by adding a flag to the Menu classes and a little logic to the event handler. Here's the full solution:
import Tkinter as Tk
import time
class firstMenu( Tk.Menu ):
def __init__( self, parent, tearoff=False ):
Tk.Menu.__init__( self, parent, tearoff=tearoff )
self.optionNum = 0 # Increments each time the menu is show, so we can see it update
self.open = False
def repopulate( self ):
print 'repopulating firstMenu'
# Clear all current population
self.delete( 0, 'last' )
# Add the new menu items
self.add_command( label='Option 1.' + str(self.optionNum+1) )
self.add_command( label='Option 1.' + str(self.optionNum+2) )
self.optionNum += 2
class secondMenu( Tk.Menu ):
def __init__( self, parent, tearoff=False ):
Tk.Menu.__init__( self, parent, tearoff=tearoff )
self.optionNum = 0 # Increments each time the menu is show, so we can see it update
self.open = False
def repopulate( self ):
print 'repopulating secondMenu'
# Clear all current population
self.delete( 0, 'last' )
# Add the new menu items
self.add_command( label='Option 2.' + str(self.optionNum+1) )
self.add_command( label='Option 2.' + str(self.optionNum+2) )
self.optionNum += 2
class Gui( object ):
def __init__( self ): # Create the TopLevel window
self.root = Tk.Tk()
self.root.withdraw() # Keep the GUI minimized until it is fully generated
self.root.title( 'Menu Tests' )
# Create the GUI's main program menus
self.menubar = Tk.Menu( self.root )
self.menubar.add_cascade( label='File', menu=firstMenu( self.menubar ) )
self.menubar.add_cascade( label='Settings', menu=secondMenu( self.menubar ) )
self.root.config( menu=self.menubar )
self.root.deiconify() # Brings the GUI to the foreground now that rendering is complete
# Add an event handler for activation of the main menus
self.menubar.bind( "<<MenuSelect>>", self.updateMainMenuOptions )
# Start the GUI's mainloop
self.root.mainloop()
self.root.quit()
def updateMainMenuOptions( self, event ):
activeMenuIndex = self.root.call( event.widget, "index", "active" ) # event.widget is a path string, not a widget instance
if isinstance( activeMenuIndex, int ):
activeMenu = self.menubar.winfo_children()[activeMenuIndex]
if not activeMenu.open:
# Repopulate the menu's contents
activeMenu.repopulate()
activeMenu.open = True
else: # The active menu index is 'none'; all menus are closed
for menuWidget in self.menubar.winfo_children():
menuWidget.open = False
if __name__ == '__main__': Gui()
The end result is that each menu's code to generate its contents, via .repopulate(), is only called once, and only if that particular menu is actually going to be shown. The method isn't called again until the whole main menu is left and re-opened. Works when navigating via keyboard too.
I'm using QtableView and QStandardItemModel to display logs on GUI to maintain proper spacing and filter logs. I created model and inserted data into it. Used QSortFilterProxyModel for filter strings.
self.tableView = QtGui.QTableView(self)
self.model = QtGui.QStandardItemModel(self)
self.proxy = QtGui.QSortFilterProxyModel(self)
self.proxy.setSourceModel(self.model)
self.tableView.setModel(self.proxy)
In a sec, nearly 100 logs are expected and should be shown on GUI. When new logs are appended, the view isn't auto scrolling and the slider stays only at the top. It doesn't give live feel for logging and user need to scroll manually to the end. So to overcome this, i used following syntax,
self.model.rowsInserted.connect(lambda: QtCore.QTimer.singleShot(5, self.tableView.scrollToBottom))
It gives live feel for logs, but the slider remains always in bottom and i'm not able to scroll up to see previous logs. Whenever i try to move the slider, it immediately comes down to bottom again. So this syntax doesn't meet my requirement. In QTextEdit, auto scrolling is proper and user friendly. I want the same scenario here on QtableView. Is there any alternative for auto scrolling which resembles like QTextEdit ?
To get the required behaviour, you can auto-scroll only when the previous scroll position is at the bottom. That way, whenever the user scrolls away from the bottom, auto-scrolling will be disabled; but when they scroll back to the bottom, auto-scrolling will be re-enabled. (NB: to quickly re-enable auto-scroll, right-click the scrollbar and select "Bottom" from the context menu).
Here is a simple demo:
from PyQt4 import QtCore, QtGui
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.table = QtGui.QTableView(self)
self.model = QtGui.QStandardItemModel(self)
self.table.setModel(self.model)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.table)
self._scroll = True
self.model.rowsAboutToBeInserted.connect(self.beforeInsert)
self.model.rowsInserted.connect(self.afterInsert)
def beforeInsert(self):
vbar = self.table.verticalScrollBar()
self._scroll = vbar.value() == vbar.maximum()
def afterInsert(self):
if self._scroll:
self.table.scrollToBottom()
def addRow(self):
self.model.appendRow([QtGui.QStandardItem(c) for c in 'ABC'])
if __name__ == '__main__':
app = QtGui.QApplication([''])
window = Window()
window.setGeometry(500, 50, 400, 300)
window.show()
timer = QtCore.QTimer()
timer.timeout.connect(window.addRow)
timer.start(200)
app.exec_()
which consist a combo box 4 buttons. Once i select an entry from combo box, it will enable a button upon clicking one button it enables the rest. I want to send a command once the buttons is enabled on clicking it.
Below is my code:
import wx
import xlrd
import os,sys,time
folderpath = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
print folderpath
site_lib_path = os.path.join(folderpath, "site_lib")
files = os.listdir(site_lib_path)
for file in files:
sys.path.append(os.path.join(site_lib_path, file))
from printercx import printercx
from resttestservice.resttestservice import UITest
class ui(wx.Frame):
"""
This Class will create a Sample Frame and Create Two Buttons on tha Panel.
"""
def __init__(self,parent,id):
"""
This Fucntion will create a Frame and a Panel which has Two buttons: "OK" and "Cancel"
"""
"""-----SALQE Connecttion-----------"""
self.connection = printercx.deviceConnection()
self.ui = UITest(self.connection)
"""-----------Window Bar Name------"""
wx.Frame.__init__(self,parent,id,'GEN-2 Tool',size=(600,500))
panel=wx.Panel(self)
"""-----------Heading-------"""
header_text = wx.StaticText(panel, label="GEN-2 Tool", pos=(250,30))
font = wx.Font(15, wx.DECORATIVE, wx.NORMAL, wx.BOLD)
header_text.SetFont(font)
wx.StaticLine(panel, pos=(10, 75), size=(690,3))
"""-----------Buttons-------"""
self.pre_button=wx.Button(panel,label="Precondition",pos=(50,250),size=(100,40))
self.act_button=wx.Button(panel,label="Action",pos=(450,250),size=(100,40))
self.pass_button=wx.Button(panel,label="Pass",pos=(50,350),size=(100,40))
self.fail_button=wx.Button(panel,label="Fail",pos=(450,350),size=(100,40))
"""-------------------------------Excel-------------------------------------------------------"""
self.mainList=[]
self.val_list=[]
dic={}
book=xlrd.open_workbook("Reference_Mapping.xlsx")
sheet=book.sheet_by_name("TestCases")
n_row= sheet.nrows-1
n_col=sheet.ncols
row=1
while row<=n_row:
smallList=[]
col=0
while col<n_col:
cel=sheet.cell(row,0)
if cel.value!="":
self.val_list.append(cel.value)
key=sheet.cell(0,col).value
val=sheet.cell(row,col).value
dic[key]=val
col+=1
smallList.append(dic.copy())
self.mainList.append(smallList)
row+=1
self.val_list= list(set(self.val_list))
"""-------------------------------------------------------------------------------------------------"""
"""-----------Combo Box with Text-------"""
text=wx.StaticText(panel, label="Test Case: ", pos=(150,130))
font = wx.Font(10,wx.DECORATIVE, wx.NORMAL, wx.BOLD)
text.SetFont(font)
self.val_list.insert(0, "Select")
self.combobox=wx.ComboBox(panel, value=self.val_list[0], pos=(300,130), choices=self.val_list,style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.onTestCaseSelection, self.combobox)
print "-----------"
def onTestCaseSelection(self,event):
if self.combobox.GetSelection()>0:
print self.combobox.GetValue()
"""---------- Compairing Key's values--------------"""
for each in range(len(self.mainList)):
for every in range(len(self.mainList[each])):
if self.mainList[each][every]['TC_ID']==self.combobox.GetValue():
if self.mainList[each][every]['Ref_ID_Pre']=="":
if self.mainList[each][every]['Ref_ID_Post']!="":
self.pre_button.Enable(False)
self.act_button.Enable(True)
self.Bind(wx.EVT_BUTTON,self.send_udw,self.act_button)
self.pass_button.Enable(True)
self.fail_button.Enable(True)
if self.mainList[each][every]['Ref_ID_Pre']!="":
if self.mainList[each][every]['Ref_ID_Post']=="":
self.pre_button.Enable(True)
self.Bind(wx.EVT_BUTTON,self.send_udw,self.pre_button)
self.act_button.Enable(False)
self.pass_button.Enable(False)
self.fail_button.Enable(False)
if self.mainList[each][every]['Ref_ID_Pre']!="":
if self.mainList[each][every]['Ref_ID_Post']!="":
action_button_cmd=self.mainList[each][every]['Ref_ID_Post']
self.pre_button.Enable(True)
self.Bind(wx.EVT_BUTTON,self.send_udw,self.pre_button)
self.act_button.Enable(False)
self.pass_button.Enable(False)
self.fail_button.Enable(False)
else:
self.disableAllControls(without=None)
def disableAllControls(self, without=None):
if without==None:
self.pre_button.Enable(False)
self.act_button.Enable(False)
self.pass_button.Enable(False)
self.fail_button.Enable(False)
def send_udw(self,event):
for each in range(len(self.mainList)):
for every in range(len(self.mainList[each])):
if self.mainList[each][every]['TC_ID']==self.combobox.GetValue():
if self.mainList[each][every]['Ref_ID_Pre']=="":
if self.mainList[each][every]['Ref_ID_Post']!="":
if self.act_button.IsEnabled()==True:
post_command=self.mainList[each][every]['Ref_ID_Post']
post_udw="ui_v3.move_to_state "+post_command+" 1"
self.connection.udw(post_udw)
if self.mainList[each][every]['Ref_ID_Pre']!="":
if self.mainList[each][every]['Ref_ID_Post']=="":
if self.pre_button.IsEnabled()==True:
post_command=self.mainList[each][every]['Ref_ID_Pre']
post_udw="ui_v3.move_to_state "+post_command+" 1"
self.connection.udw(post_udw)
if self.mainList[each][every]['Ref_ID_Pre']!="":
if self.mainList[each][every]['Ref_ID_Post']!="":
if self.pre_button.IsEnabled()==True:
post_command=self.mainList[each][every]['Ref_ID_Pre']
post_udw="ui_v3.move_to_state "+post_command+" 1"
print post_udw
self.connection.udw(post_udw)
"""----Enabling button---"""
self.pre_button.Enable(False)
self.act_button.Enable(True)
self.pass_button.Enable(True)
self.fail_button.Enable(True)
time.sleep(1)
I want to send a command once this button self.act_button.Enable(True) gets enabled.
You can bind the button's to events before you disable them. They aren't going to react to events (other than maybe mouse events) until you enable them. There is no reason to bind events when you enable the button.
If you want to call a function after the enabling process (i.e. self.act_button.Enable(True)), then just call the function right after that:
self.act_button.Enable(True)
self.myFunction(*args, **kwargs)
If you want to create some kind of custom event, then you'll want to look into how to use wx.PostEvent and wx.lib.newevent. The following resources might interest you as well:
https://wiki.wxpython.org/CustomEventClasses
https://wxpython.org/Phoenix/docs/html/events_overview.html
http://wiki.ozanh.com/doku.php?id=python:misc:wxpython_postevent_threading
I'm writing an app that has multiple instances of OptionMenu and I can't get focus to traverse properly between them. This is a two-part question.
First, my original problem was that once you selected an item from one of the menus, focus would always return to that menu every time you made a selection in a different menu. So if you selected an option in menu 1, then tabbed to menu 2 and made a selection there, the next tab would take you back to menu 1 instead of to menu 3. I "fixed" this problem with the function menu_MacGyver(), but I would like a more elegant solution.
Second, the "fixed" code still has a bug. Even though focus traverses all three menus now, the first menu selected still shows a highlight (as if it's in focus) whenever either of the other menus drops down. I'm not sure how the program is even remembering which OptionMenu was selected first, so I haven't been able to make it forget.
Here's the problem section of code:
class MyApp:
def __init__(self, parent):
self.parent = parent
self.mainFrame = Frame(parent, padx=10, pady=10)
self.mainFrame.pack(side=TOP, anchor=CENTER)
parent.bind_class("Menubutton", "<Down>",
lambda event: self.menu_MacGyver(event))
self.report_format = StringVar()
self.report_format.set("Non-spreadsheet overload report")
self.base_case_rating = StringVar()
self.base_case_rating.set("Rate B")
self.contingency_rating = StringVar()
self.contingency_rating.set("Rate B")
self.report_format_options_str = ["Spreadsheet overload report",
"Spreadsheet loading table",
"Available capacity table",
"Non-spreadsheet overload report",
"Non-spreadsheet loading table",
"Non-converged network",
"Non-spreadsheet corrective actions"]
option1 = OptionMenu(self.mainFrame,
self.report_format,
*self.report_format_options_str)
option1.config(takefocus=1)
option1.pack(side=TOP, anchor=NW)
self.rating_options_str = ["Rate A", "Rate B", "Rate C"]
option2 = OptionMenu(self.mainFrame,
self.base_case_rating,
*self.rating_options_str)
option2.config(takefocus=1)
option2.pack(side=TOP, anchor=NW)
option3 = OptionMenu(self.mainFrame,
self.contingency_rating,
*self.rating_options_str)
option3.config(takefocus=1)
option3.pack(side=BOTTOM, anchor=NW)
def menu_MacGyver(self, event):
event.widget.event_generate("<space>")
event.widget.config(takefocus=0)
event.widget.focus_set()
event.widget.config(takefocus=1)
root = Tk()
GUI = MyApp(root)
root.mainloop()
I am new to Python and Tkinter so I am trying to create a sample program to explore.
The program basically shows the names as a Label then 4 buttons will be put right next to the Label.
One of the buttons is "Delete" and what I want to do is, the button will get the name of the Label that is right next to that 'Delete" button.
The code is :
from Tkinter import *
class GUI():
def __init__(self):
self.namelist = ["Mark","Anna","Jason","Lenna",
"Leo","Zucharich","Robinson",
"AReallyLongNameThatMightExist"]
self.canvas = Canvas(width=1200,height=700)
self.canvas.pack(expand=YES,fill=BOTH)
def Friends(self):
frame = Frame(self.canvas)
frame.place(x=600,y=300)
#Frame for showing names of friends
row = 0
for x in self.namelist:
label = Label(frame,text="%s "%x)
chatButton = Button(frame,text="Chat")
delButton = Button(frame,text="Delete")
setcloseButton = Button(frame,text="Set Close")
setgroupButton = Button(frame,text="Set Group")
label.grid(row=row, column=0, sticky="W")
chatButton.grid(row=row, column=1)
delButton.grid(row=row, column=2)
setcloseButton.grid(row=row, column=3)
setgroupButton.grid(row=row, column=4)
row = row + 1
mainloop()
GUI = GUI()
GUI.Friends()
Example: If you run the code, then when you click "Delete" button next to "Mark", then the button will return "Mark".
Thanks!
Tk buttons have a command option to allow you to specify code to be run when the button is clicked. In this case you just want to pass the sibling widget name to your function. You can do this by capturing the widget name at creation time:
label = ...
delButton = Button(frame,text="Delete",
command=self.makeClosure(label))
...
def makeClosure(self, labelWidget):
return lambda: self.onClick(labelWidget)
def onClick(self, labelWidget):
print(labelWidget["text"])
In this example, when we create the delButton widget, the command is defined as a lambda that creates a closure including the label variable as it is defined at the time when this lambda is defined. Now when the delButton is clicked, this value will be passed to the onClick function which can use this to call methods on the widget at runtime.