Interactive wizard in wxpython (Phoenix) - wizard

I am trying to develop an interactive wizard in wxPython 4.0(Phoenix) with Python 3.7. Basically the wizard has 4 pages(Stages). Each time I click Next, it should run a different Python script by taking the arguments on the page. I need to display the progress of the running of script on the wizard page.
I have already developed a basic interface for wizard with 4 pages. Now I need help on
1. How to pass arguments from the Page to the Python script?
2. How to call a different Python script everytime I click Next Button on the 4 Pages of wizard? (I think I need to write code around the event ON_PAGE_CHANGING, But I am not clear how to call a different Python script everytime I click NExt Button)
3. How to display progress bar of each script on the wizard?
I am attaching the code for my Basic wizard interface. I am new to WxPython, Any help on the above 3 points is greatly appreciated.
#!/usr/bin/env python
import wx
import wx.adv
from wx.adv import Wizard as wizmod
#import images
from wx.adv import WizardPage, WizardPageSimple
import os.path
padding = 5
class wizard_page(wx.adv.WizardPage):
''' An extended panel obj with a few methods to keep track of its siblings.
This should be modified and added to the wizard. Season to taste.'''
def __init__(self, parent, title):
WizardPage.__init__(self, parent)
self.next = self.prev = None
self.sizer = wx.BoxSizer(wx.VERTICAL)
title = wx.StaticText(self, -1, title)
title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
self.sizer.Add(title, 0, wx.ALIGN_LEFT|wx.ALL, padding)
self.sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, padding)
self.SetSizer(self.sizer)
def add_stuff(self, stuff):
'''Add aditional widgets to the bottom of the page'''
self.sizer.Add(stuff, 0, wx.EXPAND|wx.ALL, padding)
def SetNext(self, next):
'''Set the next page'''
self.next = next
def SetPrev(self, prev):
'''Set the previous page'''
self.prev = prev
def GetNext(self):
'''Return the next page'''
return self.next
def GetPrev(self):
'''Return the previous page'''
return self.prev
class wizard(wx.adv.Wizard):
'''Add pages to this wizard object to make it useful.'''
def __init__(self, title, img_filename=""):
# img could be replaced by a py string of bytes
if img_filename and os.path.exists(img_filename):
img = wx.Bitmap(img_filename)
else: img = wx.NullBitmap
wx.adv.Wizard.__init__(self, None, -1, title, img)
self.pages = []
# Lets catch the events
self.Bind(wx.adv.EVT_WIZARD_PAGE_CHANGED, self.on_page_changed)
self.Bind(wx.adv.EVT_WIZARD_PAGE_CHANGING, self.on_page_changing)
self.Bind(wx.adv.EVT_WIZARD_CANCEL, self.on_cancel)
self.Bind(wx.adv.EVT_WIZARD_FINISHED, self.on_finished)
def add_page(self, page):
'''Add a wizard page to the list.'''
if self.pages:
previous_page = self.pages[-1]
page.SetPrev(previous_page)
previous_page.SetNext(page)
self.pages.append(page)
def run(self):
self.RunWizard(self.pages[0])
def on_page_changed(self, evt):
'''Executed after the page has changed.'''
if evt.GetDirection(): dir = "forward"
else: dir = "backward"
page = evt.GetPage()
print ("page_changed: %s, %s\n" % (dir, page.__class__))
def on_page_changing(self, evt):
'''Executed before the page changes, so we might veto it.'''
if evt.GetDirection(): dir = "forward"
else: dir = "backward"
page = evt.GetPage()
print ("page_changing: %s, %s\n" % (dir, page.__class__))
def on_cancel(self, evt):
'''Cancel button has been pressed. Clean up and exit without continuing.'''
page = evt.GetPage()
print ("on_cancel: %s\n" % page.__class__)
# Prevent cancelling of the wizard.
if page is self.pages[0]:
wx.MessageBox("Cancelling on the first page has been prevented.", "Sorry")
evt.Veto()
def on_finished(self, evt):
'''Finish button has been pressed. Clean up and exit.'''
print ("OnWizFinished\n")
if __name__ == '__main__':
app = wx.App() # Start the application
# Create wizard and add any kind pages you'd like
mywiz = wizard('Simple Wizard', img_filename='wiz.png')
page1 = wizard_page(mywiz, 'Stage 1') # Create a first page
#page1.add_stuff(wx.StaticText(page1, -1, 'Hola'))
page1.add_stuff(wx.CheckBox(page1,-1,'Argument1',(35,40),(150,20)))
page1.add_stuff(wx.CheckBox(page1,-1,'Argument2',(35,60),(150,20)))
page1.add_stuff(wx.CheckBox(page1,-1,'Argument3',(35,80),(150,20)))
mywiz.add_page(page1)
# Add some more pages
mywiz.add_page( wizard_page(mywiz, 'Stage 2') )
mywiz.add_page( wizard_page(mywiz, 'Stage 3') )
mywiz.add_page( wizard_page(mywiz, 'Stage 4') )
mywiz.run() # Show the main window
# Cleanup
mywiz.Destroy()
#del app
app.MainLoop()
del app

Related

Tkinter Not Opening Window

I am creating a program that allows a user to make a custom dice, but when I open a GUI window with a button that calls the backend dice roll logic, it breaks. In other words, the window doesn't open, and the code just runs in the terminal. It doesn't happen when the button is clicked like I want it to, instead when I run the code, it doesn't open any GUI window and the code executes in the terminal. The code works without the GUI, and if i take out the dice button callback, the GUI works but together it doesn't.
Any help is appreciated!
import random
import tkinter as tk
def dice_roll():
dice = []
x = 0
# used to check if the input is a whole number, if it isn't, you get a message
while True:
while x == 0:
try:
SIDE_AMT = int(input("How many sides would you like? (min is 2, max is infinite): ")) # amt is amount
x = 1
except ValueError:
print("Sorry it has to be a whole number.")
if SIDE_AMT > 1:
for side in range(SIDE_AMT):
print(f"What would you like side {side + 1} to be?:")
dice.append(str(input()))
break
else:
print("You can't have a dice with one side!")
x = 0
# roll function
def roll():
dice_side = random.choice(dice)
print(f"I choose {dice_side}!")
roll_num = 0
while True:
if roll_num == 0:
spin_it = str(input("Type 'roll' if you would like to roll the dice: "))
if spin_it == "roll":
roll()
else:
print("Sorry, you have to type roll correctly.")
roll_num += 1
elif roll_num == 1:
while True:
spin_it = str(input("Type 'roll' if you would like to roll the dice again!: "))
if spin_it == "roll":
roll()
else:
print("Sorry, you have to type roll correctly.")
if __name__ == '__main__':
gui = tk.Tk()
gui.title("Dice Roll")
gui.geometry("1912x1090")
gui.configure(bg='#a2a2a1', borderwidth=5,
relief="raised")
# title
title = tk.Label(gui, text='Unique Dice', font=("Times
New Roman", 52))
title.configure(bg='#a2a2a1', fg='#195190',
borderwidth=3, relief='raised')
# make a dice?
dice = tk.Button(gui,
text="Yes!",
fg="red",
command=dice_roll())
no_dice = tk.Button(gui,
text="No",
fg="red",
command=quit)
# frame = tk.Frame(gui, height=200, width=200)
# frame['borderwidth'] = 10
# frame['relief'] = 'sunken'
# frame.pack()
dice.pack()
no_dice.pack()
title.pack()
gui.mainloop()
you may want to do something like this:
import tkinter as tk
from random import choice
root = tk.Tk()
root.geometry('400x600')
root.resizable(False, False)
root.config(bg='light blue')
dice_numbers = [1, 2, 3, 4, 5, 6]
rolled_nums = []
def roll():
if len(rolled_nums):
rolled_nums[0].pack_forget()
rolled_nums.pop(0)
chosen_number = choice(dice_numbers)
text = tk.Label(root, text=f'{chosen_number}',
font='arial 500 bold', bg='light blue')
text.pack()
rolled_nums.append(text)
button = tk.Button(root, text='Roll Dice!', font='arial 20 bold', relief='raised', width='300',
bg='dark red', fg='black', command=lambda: roll())
button.pack()
root.mainloop()
fell free to adjust this code and if you have questions -> ask

Trying to Refresh a ScrolledText and combobox from tkinter python

I have a code that will read in a json file from a method. What I want to do is. Have this method called when the program is opened. And called again when the user presses a button which send a json request to a server and then changes the database there. Now when the user presses the button I want to refresh the values that are inside the combobox and scrolledtext widgets. I just can seem to do that correctly. It either does not do anything or adds extra things to the bottom.
What I would like is to clear the scrolledtext and the combobox value and rewrite them form the new Json file.
What I have so far.
from tkinter import *
from tkinter.ttk import *
from tkinter import scrolledtext
from tkinter import messagebox
# AI devices imports
from SmartAdFSM import ADControlSystem as aic
from SmartAdFSM.AdUtility import AdHelperMethods as adm
# Varialbes that are collected from differnt APIs
# TODO:Replace with real ads from Google/Yahoo/Facebook
# TODO: Create method to gather all avalialbe ads from service providers and create
# 1: list of all ads form API, '(Yahoo, Google, Facebook)
# 2: FSM for all ads
# List for ads
# They are broken up first by service provider then added into a master list
currentAds = [] # This holds every add from every service provider.
apiYahooAds = [] # This holds every yahoo add
jsonFile = "TestAds/YahooAd.json"
# Get the initial setup and read the new info from Yahoo API
adm.CreateYahooAdList(jsonFile, apiYahooAds, currentAds)
# Add ad values into the list for dropdown and fsm
# Initial set up of the UI
ddMenuValues = [] # names of each ad
adTitles = [] # The FSM for each ad
def activateClicked():
target = dropdownWidget.get()
msg = "{} Ad is now active".format(target)
for targetAd in currentAds:
if target == targetAd.title:
aic.controlFSM(targetAd, "activate")
messagebox.showinfo('Action', msg)
# collect the updated API from yahoo API to update the UI
adm.CreateYahooAdList(jsonFile, apiYahooAds, currentAds)
adm.UpdateUI(adTitleViewWidget,dropdownWidget,adTitles,ddMenuValues,currentAds)
break
def deactivateClicked():
target = dropdownWidget.get()
msg = "{} Ad in now inactive".format(target)
for targetAd in currentAds:
if target == targetAd.title:
aic.controlFSM(targetAd, "pause")
messagebox.showinfo('Action', msg)
# collect the updated API from yahoo API to update the UI
adm.CreateYahooAdList(jsonFile, apiYahooAds, currentAds)
break
def endClicked():
target = dropdownWidget.get()
msg = "{} Ad in now ended".format(target)
for targetAd in currentAds:
if target == targetAd.title:
aic.controlFSM(targetAd, "delete")
messagebox.showinfo('Action', msg)
# collect the updated API from yahoo API to update the UI
adm.CreateYahooAdList(jsonFile, apiYahooAds, currentAds)
break
window = Tk()
window.title("SmartAd Manager IgniterLabs")
window.geometry("900x500")
# Widgets
mainLabel = Label(window, text="Welcome to SmartAd management Tool",
font=("Arial Bold", 12))
activeAdsLabel = Label(window, text="Current Ads Available")
# Activate button
activateButton = Button(window, text="Activate Ad",
command=activateClicked)
# Deactivate Button
deactivateButton = Button(window, text="Deactivate Ad",
command=deactivateClicked)
# End Button
endButton = Button(window, text="End Ad",
command=endClicked)
# Quit button
quitButton = Button(window, text="Quit",
command=quit)
# Combo box to select the Ad
dropdownWidget = Combobox(window)
# Set the dropdownmenu contents
# Text filed for user
adTitleViewWidget = scrolledtext.ScrolledText(window)
# set the textfeild' contents
adm.UpdateUI(adTitleViewWidget, dropdownWidget, adTitles, ddMenuValues,currentAds)
# Set main label position on grid
mainLabel.grid(column=0, row=0)
dropdownWidget.grid(column=0, row=1)
activateButton.grid(column=1, row=1)
deactivateButton.grid(column=2, row=1)
endButton.grid(column=3, row=1)
activeAdsLabel.grid(column=0, row=2)
adTitleViewWidget.grid(column=0, row=3, columnspan=3)
quitButton.grid(column=0, row=4)
window.mainloop()
And here is the helper methods that i am using:
def CreateYahooAdList(jsonSource, yahooAdList, adList):
# Test Ad simulate call from API
# TODO: Create call to API for Yahoo Ad to get every ad that is available
readFromAPI = jsonSource
# read in the file
parsedFile = yjp.readinJson(readFromAPI)
# create objects for each ad and add them into the Yahoo Ad list
yjp.createAdObjects(yahooAdList, parsedFile)
# Then add all the new Yahoo parsed ads (Now Ad Objects) into the myAds list
for ad in yahooAdList:
adList.append((ad))
'''
This method will get values from a Json file
In the future it will pull it off the Yahoo API
#:param textFeildValues = adTitles[] from SimpleUIControler
#:param comboValues = ddMenuValues[] from SimpleUIControler
#:param ads = currentAds from SimpleUIControler
'''
def UpdateUIValues(textFeildValues, comboValues, ads):
for ad in ads:
title = ad.title
status = ad.status
comboValues.append(title)
textFeildValues.append(title + "-" + status + "\n")
def UpdateUI(adTitleViewWidget, dropdownWidget, adTitle, dropdownValues, currentAds):
# First update the values to be used
UpdateUIValues(adTitle, dropdownValues, currentAds)
# Clear exsiting UI
adTitleViewWidget.delete(1.0, END)
for ad in adTitle:
adTitleViewWidget.insert(END, ad)
dropdownWidget['values'] = dropdownValues
# The init value
dropdownWidget.current(0)
Ok so I found an answer to this that works, may not be the best thing, but hey.
So on a button click you need to clear the contents of the box then add the new content into the box.
def getItemsPerLine(dropdownValues, listboxWidget):
# Clear the list
listboxWidget.delete(0,'end')
x = 1
for item in dropdownValues:
listboxWidget.insert(x, item)
x += 1

Working with coroutines in Python Tornado Web Server

I am working on an autonomous car implementation for a web browser game with Python 2x. I use Tornado Web Server to run game on localhost and I post and receive data from game with JSON data format in the function called "FrameHandler" and also I determine what the act of car should be in "to_dict_faster()" function.
Here, my problem is that I can write data to text file which is hold in speed_data variable in specific time interval with help of a coroutine. However, I can't dump JSON data to function in this specific time interval because "FrameHandler" acts like While True and it always requests data to dump. What I am trying to do is sending desired acts as writing text file in specific time interval while not changing flow frame handler because it affects FPS of the game.
I am trying to figure out How can I do that for a long time any help would be great here:
#gen.coroutine
def sampler():
io_loop = tornado.ioloop.IOLoop.current()
start = time.time()
while True:
with open("Sampled_Speed.txt", "a") as text_file:
text_file.write("%d,%.2f\n" % (speed_data, ((time.time() - start))))
yield gen.Task(io_loop.add_timeout, io_loop.time() + period)
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.redirect("/static/v2.curves.html")
class FrameHandler(tornado.web.RequestHandler):
def post(self):
global speed_data
data = json.loads(self.get_arguments("telemetry")[0])
ar = np.fromstring(base64.decodestring(self.request.body), dtype=np.uint8)
image = ar.reshape(hp.INPUT_SIZE, hp.INPUT_SIZE, hp.NUM_CHANNELS)
left, right, faster, slower = data["action"]
terminal, action, all_data, was_start = (
data["terminal"],
Action(left=left, right=right, faster=faster, slower=slower),
data["all_data"],
data["was_start"]
)
for i in range(len(all_data)):
data_dict=all_data[i]
speed_data = data_dict[u'speed']
position_data=data_dict[u'position']
result_action = agent.steps(image, 0.1, terminal, was_start, action, all_data)
if speed_data < 4000:
self.write(json.dumps(result_action.to_dict_faster()))
else:
self.write(json.dumps(result_action.to_dict_constant()))
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
(r"/frame", FrameHandler),
(r"/static/(.*)", tornado.web.StaticFileHandler, {"path": static_path})
], debug=True)
if __name__ == "__main__":
app = make_app()
if "SERVER_PORT" in os.environ:
port = int(os.environ["SERVER_PORT"])
else:
port = 8880
print "LISTENING ON PORT: %d" % port
app.listen(port)
tornado.ioloop.IOLoop.current().run_sync(sampler)
tornado.ioloop.IOLoop.current().start()
You can move file writing to a different thread (using tornado's run_on_executor for example), so python interpreter will automatically switch from Sampler to main thread with FrameHandler on write. But you have to use thread-safe speed_data variable, I've used stdlib Queue.Queue as an example:
class Handler(tornado.web.RequestHandler):
#gen.coroutine
def get(self):
global speed_data
speed_data.put("REALLY BIG TEST DATA\n")
self.finish("OK")
class Sampler():
executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
def __init__(self, queue):
self._q = queue
#run_on_executor
def write_sample(self):
with open("foobar.txt", "w") as f:
while True:
data = self._q.get()
f.write(data)
if __name__ == '__main__':
application = Application(
[("/status", Handler)]
)
server = HTTPServer(application)
server.listen(8888)
speed_data = Queue.Queue()
smp = Sampler(speed_data)
IOLoop.current().add_callback(smp.write_sample)
IOLoop.current().start()

Display html using a wxPython control

I am trying to display rich text (or html) in a segment of a wx python frame
I have tried the rtf control with no luck (see here). I am now trying the html route, but in the only examples I can find the html is display in a window that takes over the whole frame; for example from here
import wx
import wx.html
class MyHtmlFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, -1, title)
html = wx.html.HtmlWindow(self)
if "gtk2" in wx.PlatformInfo:
html.SetStandardFonts()
html.SetPage(
"Here is some <b>formatted</b> <i><u>text</u></i> "
"loaded from a <font color=\"red\">string</font>.")
app = wx.PySimpleApp()
frm = MyHtmlFrame(None, "Simple HTML")
frm.Show()
app.MainLoop()
Is it possible to display html in a textbox or some other suitable control that I can incorporate into my application?
I want the screen to look like that below. Can the wx.TextCtrl be replaced by an HTML window or something?
import wx
class MainFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, -1, title)
panel = MainPanel(self)
panel.txt_comments.SetValue(
"Here is some <b>formatted</b>"
"<i><u>text</u></i> "
"loaded from a "
"<font color=\"red\">string</font>.")
class MainPanel(wx.Panel):
def __init__(self, frame):
wx.Panel.__init__(self, frame)
txt_style = wx.VSCROLL|wx.HSCROLL|wx.TE_READONLY|wx.BORDER_SIMPLE
self.txt_comments = wx.TextCtrl(self, size=(300, 150), style=txt_style)
cmd_update = wx.Button(self, wx.ID_REFRESH)
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(self.txt_comments, flag=wx.ALL, border=10)
main_sizer.Add(cmd_update, flag=wx.ALL, border=10)
self.SetSizerAndFit(main_sizer)
app = wx.App()
frm = MainFrame(None, "Screen layout")
frm.Show()
app.MainLoop()
This must be somewhat close to an utter minimum of code.
#!/usr/bin/env python
import wx
import wx.html as html
#----------------------------------------------------------------------
ID_New = wx.NewId()
ID_Exit = wx.NewId()
#----------------------------------------------------------------------
class MyParentFrame(wx.MDIParentFrame):
def __init__(self):
wx.MDIParentFrame.__init__(self, None, -1, "MDI Parent", size=(600,400))
self.winCount = 0
menu = wx.Menu()
menu.Append(ID_New, "&New Window")
menu.AppendSeparator()
menu.Append(ID_Exit, "E&xit")
menubar = wx.MenuBar()
menubar.Append(menu, "&File")
self.SetMenuBar(menubar)
self.CreateStatusBar()
self.Bind(wx.EVT_MENU, self.OnNewWindow, id=ID_New)
self.Bind(wx.EVT_MENU, self.OnExit, id=ID_Exit)
def OnExit(self, evt):
self.Close(True)
def OnNewWindow(self, evt):
self.winCount = self.winCount + 1
win = wx.MDIChildFrame(self, -1, "Child Window: %d" % self.winCount)
self.html = html.HtmlWindow(win, -1)
self.html.SetPage(
"Here is some <b>formatted</b> <i><u>text</u></i> "
"loaded from a <font color=\"red\">string</font>.")
#----------------------------------------------------------------------
if __name__ == '__main__':
class MyApp(wx.App):
def OnInit(self):
frame = MyParentFrame()
frame.Show(True)
self.SetTopWindow(frame)
return True
app = MyApp(False)
app.MainLoop()
I expect the main lines to note are these:
win = wx.MDIChildFrame(self, -1, "Child Window: %d" % self.winCount)
self.html = html.HtmlWindow(win, -1)
self.html.SetPage(
"Here is some <b>formatted</b> <i><u>text</u></i> "
"loaded from a <font color=\"red\">string</font>.")
win is the frame in which you want to house the HTMLWindow.
Notice that win is the first parameter to HTMLWindow.
I used wxWindow quite a bit several years ago, and I've lost most of my skills. Now I remember that the secret to getting a leg up is to start with the demo codes. I used a couple of them this time.
Edit on the basis of comments:
import wx
import wx.html as html
class MainFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, -1, title)
panel = MainPanel(self)
class MainPanel(wx.Panel):
def __init__(self, frame):
wx.Panel.__init__(self, frame)
txt_style = wx.VSCROLL|wx.HSCROLL|wx.TE_READONLY|wx.BORDER_SIMPLE
self.html = html.HtmlWindow(self, -1, size=(300, 150), style=txt_style)
self.html.SetPage(
"Here is some <b>formatted</b>"
"<i><u>text</u></i> "
"loaded from a "
"<font color=\"red\">string</font>.")
app = wx.App()
frm = MainFrame(None, "Screen layout")
frm.Show()
app.MainLoop()
wx.html.HtmlWindow or wx.html2.WebView are much like other child widgets in wxPython, in that they need a parent, and the size and position need to be managed in some way, and so on. That also means that you can replace the use of TextCtrl in your sample with one of those widgets, and replace SetValue with SetPage and it should work the way you want. See the docs for specifics and give it a try.

How does one get widget values with a button in ipython

I have a function createWidgets whose purpose is to take a list of strings and create a list of containers for each string -> 1 container = a textbox and checkbox. Each container is then put into a large container.
What I am trying to do is append a button to the container that on_click takes all the "True"s and puts all the modified strings and puts them in a dataframe
widgelist = e.options
txtBox_type = 'text_widget' # Define if Area box o regular txtbox
bigContainer = createWidgets(widgelist, txtBox_type)
Function
def createWidgets(widgelist, txtBox_type):
#containerList = []
i = 0
for k in widgelist:
## Build Container widgets
chBox_Widget = widgets.CheckboxWidget(description = str(i),value = False,)
if txtBox_type == 'textA_widget': # Check wether txtBox should be an area txt box or not.
txt_Widget = widgets.TextareaWidget( description = str(i), value = k)
else:
txt_Widget = widgets.TextWidget( description = str(i), value = k)
container = widgets.ContainerWidget()
container.children = [chBox_Widget, txt_Widget]
containerList.append(container)
i+= 1
button = widgets.ButtonWidget(description = 'Add')
bigContainer = widgets.ContainerWidget()
bigContainer.children = containerList
return bigContainer
I have gone to many websites and spent many days on this help is very much appreciated
As near as I can interpret the question, the code below should provide an answer:
import IPython.html.widgets as widgets
from IPython.display import display, clear_output
import pandas as pd
df = pd.DataFrame(columns=['Thing'])
def createWidgets(widgelist):
## Each CheckboxWidget and TextWidget are enclosed in a subwidget. We use a
## list comprehension to construct a list of these subwidgets.
containerList = [
widgets.ContainerWidget(children=(widgets.CheckboxWidget(description=k)
widgets.TextWidget(value=k)))
for k in widgelist]
bigContainer = widgets.ContainerWidget(children=containerList)
## To arrange the CheckboxWidget in a row with the TextWidget, we have to
## first display them, then remove_class('vbox') and add_class('hbox'). This
## bit of awkwardness in the IPython version 2.x notebook will hopefully
## be fixed in version 3.x. Displaying bigContainer also displays it's children.
display(bigContainer)
for c in containerList:
c.remove_class('vbox')
c.add_class('hbox')
return bigContainer
widgelist = ['ThingA', 'ThingB', 'ThingC', 'ThingD']
bigContainer = createWidgets(widgelist, txtBox_type)
## Callback for button.on_click.
def add_to_dataframe(a):
# The children of bigContainer are also containers,
# each with first child a CheckboxWidget and second
# child a TextWidget. We iterate through them and
# if checked, add the text to the dataframe df as
# an additional row.
for c in bigContainer.children:
if c.children[0].value:
df.loc[len(df)+1] = (c.children[1].value,)
display(df)
clear_output()
display(df)
button = widgets.ButtonWidget(description = 'Add')
button.on_click(add_to_dataframe)
display(button)
Here is a screen clip of the widget area and output after adding a few rows to the dataframe.
I would have designed the code to do this somewhat differently, but I tried to stay
close to your code organization.
This is updated version for Ipython3 on jupyternotebooks 4
Just rename:
widgets.ContainerWidget ->widgets.Box
widgets.CheckboxWidget -> widgets.Checkbox
widgets.TextWidget -> widgets.Text
Reference: [https://ipython.org/ipython-doc/3/whatsnew/version3_widget_migration.html]