my question is about interactive Jupyter notebooks.
I want to display JavaScript button and print something to cell as result of button click.
We can do this easely with ipywidgets:
def OnClick(b=None): print 'qq'
b = widgets.Button(description='Button')
b.on_click(OnClick)
display(b)
But when we jumps to pure JavaScript things goes wrong. I.e. I have JavaScript Button, in on_click() event handler I use kernel interaction like:
var kernel = IPython.notebook.kernel;
kernel.execute('onClick()');
Callback is called successfuly (I checked by beep), but print produce no output in cell, where by button is displayed. So I suppose there should be some magic (like everyting in Python world!) to acceess print area, could you please help me to cast it?
The key is to use Output widget
from ipywidgets import widgets
from IPython.display import display, HTML
out = widgets.Output()
def OnClick():
with out:
print 'QQQ'
display(HTML('<a onclick="IPython.notebook.kernel.execute(\'OnClick()\')">Click!</a>'))
display(out)
Related
I have several shapes in LO Calc and I need those shapes to change their sizes when they are mouse clicked: the first click enlarges the shape, the second click restores the original size.
I'm trying to do this with a macro assigned to those shapes. My problem and my question: how to determine within a macro which shape has been clicked?
I know how to get the current selected shape:
dim doc as object
doc = ThisComponent
someVar = doc.CurrentSelection...
But a shape when clicked is not getting selected and this method is not working.
I tried to add a parameter for the event object to the macro:
sub ChangeSize( oEvent )
But this produces a message about wrong number of parameters.
Is there a way to detect the caller of a macro in LO Basic? Or maybe another way to implement size changing with a mouse click?
P.S. One can use a separate button for calling the macro and click this button after selecting the needed shape, but this way is less convenient.
EDIT: As I guessed below in the comments, the described task can be solved via the mouse and shape coordinates. The key points for the solution I found here:
How to get Document-Coordinates from a Mouse Click in an OpenOffice BASIC Macro
Instead of detecting the caller, assign a different one-line macro for each shape clicked event.
Sub ShapeClickedA
ChangeSize("ShapeA")
End Sub
Sub ShapeClickedB
ChangeSize("ShapeB")
End Sub
Related: LibreOffice macro showing simple TextBox shape
P.S. After answering, I realized you asked the linked question as well. How is this different, and is the other answer not satisfactory?
I cannot figure out (or find an example) how to perform the following simple thing in the LibreOffice Calc 6.2:
I have a drawing shape (e.g. a simple rectangle) in a sheet (call it ShapeA) and a textbox shape in another sheet (call it TextboxB). I want to do the following: when I click on the ShapeA, the TextboxB must appear on the screen (without changing the current sheet, maybe in a dialog box) and then be closed with a mouse click.
I guess the macro associated with ShapeA could look something like this:
Sub Main
oDrawPage = ThisComponent.getDrawPage()
oTb = oDrawPage.getByName("TextBoxB")
oTb.show()
End Sub
Could someone advise what I should put into this macro to accomplish the described task?
UPDATE: What I want to accomplish ( in reply to Jim K.).
I have a very cluttered diagram with many shapes. Each shape has some textual information associated with it. There is not enough space on each shape or around it to contain this info. So there is must be a way to display this info about each shape. Also this information should be displayed in a preformatted way (it contains code and other structured info).
My plan is to create a textbox with the relevant information for each diagram shape, place these textboxes in other sheet and have a possibility, when viewing diagram, to click on any shape and view the associated info in the poped up textbox without leaving the diagram, and then close the textbox with a simple action (e.g. by clicking on it).
Does this task sound feasible to be realized with the LO's shapes and macros?
How about this: Put everything on the same sheet but keep the text boxes hidden until needed.
Use the following code adapted from https://ask.libreoffice.org/en/question/93050/how-can-i-hideshow-a-shape-of-my-spreadsheet-using-a-macro/.
Sub ShapeClickedA
ShowHideShape("TextBoxA")
End Sub
Sub ShapeClickedB
ShowHideShape("TextBoxB")
End Sub
Sub ShowHideShape(shapeName As String)
oDrawPage = ThisComponent.getSheets().getByName("Sheet1").getDrawPage()
For iShape = 0 To oDrawPage.Count - 1
oShape = oDrawPage.getByIndex(iShape)
If oShape.Name = shapeName Then
If oShape.Visible Then
oShape.Visible = 0 'Not Visible
Else
oShape.Visible = 1 'Visible
End If
End If
Next iShape
End Sub
If you haven't yet, set the names of the text boxes by right-clicking and choosing Name... Then right click on both ShapeA and TextBoxA and assign the macro ShapeClickedA. Do likewise for other pairs of shapes. The result works like this:
Before anything is clicked.
Click on ShapeA. (To close it again, click on either ShapeA or TextBoxA). ShapeB functions similarly.
It's also possible to display both at the same time.
This is potentially a bug, though perhaps I'm misunderstanding something.
Brief description
Basically, I have found that using "Shift+Arrows" to do multiple selection in a Gtk.TreeView does not work correctly after changing the selection using Gtk.TreeSelection.select_iter. On the other hand, if you change the selection by clicking on a row and then pressing "Shift+Arrows", the selection behaves as one would expect.
I should note that if you change the selected row by calling Gtk.TreeSelection.select_iter, the UI updates as you would expect and calling Gtk.TreeSelection.get_selected_rows() returns the rows it should. It's only when you then try to select multiple rows using the arrow keys that you get strange behavior.
This is perhaps best illustrated in this self contained example, which I've tried to make as simple as possible:
Code
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class TreeViewBug(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
self.connect('destroy', Gtk.main_quit)
# Create model consisting of row path and a name
self.treeModel = Gtk.ListStore(int, str)
self.treeModel.append([0, 'alice'])
self.treeModel.append([1, 'bob'])
self.treeModel.append([2, 'chad'])
self.treeModel.append([3, 'dan'])
self.treeModel.append([4, 'emma'])
self.treeView = Gtk.TreeView()
self.treeView.append_column(Gtk.TreeViewColumn('path', Gtk.CellRendererText(), text=0))
self.treeView.append_column(Gtk.TreeViewColumn('name', Gtk.CellRendererText(), text=1))
self.treeView.set_model(self.treeModel)
# Allow for multiple selection
self.treeView.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
self.add(self.treeView)
def run(self):
self.show_all()
# Focus the TreeView so we can test multiple select via keyboard without clicking on a row
self.treeView.grab_focus()
# Manually change the selected row to the row with "chad"
chadIter = self.treeModel[2].iter
self.treeView.get_selection().select_iter(chadIter)
print('Press "Shift+Down" and see what happens')
print(' it should select "chad, dan", but instead it selects "bob, chad"')
print('Afterwards, try clicking on "chad" and then pressing Shift+Down. It should behave normally')
Gtk.main()
if __name__ == '__main__':
tv = TreeViewBug()
tv.run()
Things I've tried
I initially encountered the bug when my code changed the selected row via Gtk.TreeSelection.select_iter in response to a button click.
I've also tried:
adding a custom select function (Gtk.TreeSelection.set_select_function)
clearing the selection before changing it (Gtk.TreeSelection.unselect_all)
changing the selection asynchronously (GLib.idle_add).
redrawing TreeView after changing selection
Speculations
I'm guessing that TreeView/TreeViewSelection has some internal state variable tracking selection and row that, for some reason, isn't getting properly updated when TreeSelection.select_iter is called. These variables are probably related to UI features, because TreeSelection.get_selected_rows still works properly. Also it makes sense the UI would need additional state information since the UI logic of multiple selection depends on previous UI interaction (Shift+Down behaves differently when extending a selection depending on whether you initially selected upwards or downwards)
Because a Gtk.TreeView uses MVC, you actually need to set the cursor of the treeview. This may affect the rest of the program, depending on what you are doing. Example:
#chadIter = self.treeModel[2].iter
#self.treeView.get_selection().select_iter(chadIter)
path = 2
column = self.treeView.get_column(0)
edit = False
self.treeView.set_cursor(path, column, edit)
This a follow-up question to Console output on Installation screen?
I've configured a screen that contains a Text area component ("log.display") that should display what happened during my installation. The installation runs in a script that is attached to this screen. After finishing an installation step I do something like this (displayLog is initialized before):
displayLog = displayLog + currentStep + " done. \n";
context.setVariable("log.display",displayLog);
Unfortunatelly the Text area component is not updated by this. What can (must) I do to update the Text area dynamically from my script?
EDIT:
I found:
formPanelContainer = (FormPanelContainer)context.getScreenById(<screenID>);
formPanelContainer.getFormEnvironment().reinitializeFormComponents();
this seems to work, but there is one problem with that: If the "log" displayed with this solution contains more lines than the Text area can display, it shows the vertical scrollbar but doesn't scroll to the last line automatically. Is there a way to let the Text area do that?
And another question: Is it possible to ask context for the current screen without specifying a screenID (what can change)?
thanks!
Frank
The solution for my problem seems to be: get the ConfigurationObject of the TextArea component:
FormPanelContainer formPanelContainer = (FormPanelContainer)context.getScreenById(<ScreenID>);
FormEnvironment formEnvironment = formPanelContainer.getFormEnvironment();
FormComponent logComponent = formEnvironment.getFormComponentById(<TextAreaComponentID>);
JTextArea logComponentObject = (JTextArea)logComponent.getConfigurationObject();
and each time, something has to be logged:
logComponentObject.append("Text to log" + "\n");
logComponentObject.setCaretPosition(logComponentObject.getDocument().getLength());
This works fine in my setup.
I'm just starting out with wxPython and this is what I would like to do:
a) Show a Frame (with Panel inside it) and a button on that panel.
b) When I press the button, a dialog box pops up (where I can select from a choice).
c) When I press ok on dialog box, the dialog box should disappear (destroyed), but the original Frame+Panel+button are still there.
d) If I press that button again, the dialog box will reappear.
My code is given below. Unfortunately, I get the reverse effect. That is,
a) The Selection-Dialog box shows up first (i.e., without clicking on any button since the TopLevelframe+button is never shown).
b) When I click ok on dialog box, then the frame with button appears.
c) Clicking on button again has no effect (i.e., dialog box does not show up again).
What am I doing wrong ? It seems that as soon as the frame is initialized (even before the .Show() is called), the dialog box is initialized and shown automatically.
I am doing this using Eclipse+Pydev on WindowsXP with Python 2.6
============File:MainFile.py===============
import wx
import MyDialog #This is implemented in another file: MyDialog.py
class TopLevelFrame(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,"Test",size=(300,200))
panel=wx.Panel(self)
button=wx.Button(panel, label='Show Dialog', pos=(130,20), size=(60,20))
# Bind EVENTS --> HANDLERS.
button.Bind(wx.EVT_BUTTON, MyDialog.start(self))
# Run the main loop to start program.
if __name__=='__main__':
app=wx.PySimpleApp()
TopLevelFrame(parent=None, id=-1).Show()
app.MainLoop()
============File:MyDialog.py===============
import wx
def start(parent):
inputbox = wx.SingleChoiceDialog(None,'Choose Fruit', 'Selection Title',
['apple','banana','orange','papaya'])
if inputbox.ShowModal()==wx.ID_OK:
answer = inputbox.GetStringSelection()
inputbox.Destroy()
There are a number of ways to do this, but to make the least number of changes to your code,
Change def start(parent): to
def start(parent, evt):
And change button.Bind(wx.EVT_BUTTON, MyDialog.start(self)) to
button.Bind(wx.EVT_BUTTON, lambda evt: MyDialog.start(self, evt))
That is, the second argument in Bind needs to be a function that takes and event, and you need to create the dialog box when the button is clicked. lambda makes this a function that also takes parent and evt (you can also use functools.partial for version >2.5), and then when the button is clicked, start will be called to create the dialog.
I'm not quite sure what's going on in your code, but it seems that you're calling start and creating the dialog in your initial call to Bind, and then passing the return value from start, None to Bind.
Note 1
In more detail, the reason to use the lambda here is that Bind should have a form like Bind(event, handler) where event is a wx.PyEventBinder, like wx.EVT_BUTTON, and handler is a function like foo(evt) where evt is a wx.Event or wx.CommandEvent. (There's no recursion here, as you're just saying what to do when something happens, but that thing hasn't happened yet, so the event hasn't been created. When the event does happen, it will be represented by a wx.Event, which will have information about the event, like where the mouse was when it was clicked, etc.)
Note 2
In my answer I tried to answer your question with minimal changes as I thought that would be easiest. Maybe the code below is more clear (and maybe it's generally clearest to handle events within the widget that creates them):
def start2(parent):
inputbox = wx.SingleChoiceDialog(parent,'Choose Fruit', 'Selection Title',
['apple','banana','orange','papaya'])
if inputbox.ShowModal()==wx.ID_OK:
answer = inputbox.GetStringSelection()
inputbox.Destroy()
class TopLevelFrame2(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,"Test",size=(300,200))
panel=wx.Panel(self)
button=wx.Button(panel, label='Show Dialog', pos=(130,20), size=(60,20))
# Bind EVENTS --> HANDLERS.
button.Bind(wx.EVT_BUTTON, self.OnClick)
def OnClick(self, evt):
start2(self)