Dash modal with multiple buttons that open it - python

Following this part of the docs: https://dash-bootstrap-components.opensource.faculty.ai/l/components/modal I've created a modal in my Dash app. The trigger for the modal will be dynamically rendered thumbnails. When any of them is clicked, the modal should open and display the image from the thumbnail as it's body.
Is is possible, inside Dash, to have multiple buttons (I don't know how many will there be, depending on how many thumbnails in the database) that will all open the same modal dialog and pass some of their data to the modal (such as img src in my case)?
The input in the example above is simple:
[
Input("open", "n_clicks"), Input("close", "n_clicks")
],
but in reality I don't know how many will there be and can't hardcode an ID.
Any suggestions?

Yes, you can have multiple buttons open a modal. Just as you showed, the callback would have an Input for each one. No, you cannot create them dynamically. Dash does not play well with any ID that is not in the layout at the start of running the app.

Create a set of buttons dynamically using the below list comprehension:
[dcc.Button(x, id={'type': 'thumbnail_button', 'index': x}) for x in thumbnail_list]
Use the pattern-matching callback to open modal when any of these buttons are clicked:
#app.callback(
Output('your-modal', 'is_open'),
[Input({'type': 'thumbnail_button', 'index': ALL}, 'n_clicks')]
)
def handle_button_click(n_clicks):
invoker = [p['prop id'] for p in dash.callback_context.triggered][0]
invoker_type = json.loads(invoker.split('.')[0])['type']
invoker_index = json.loads(invoker.split('.')[0])['index']
if invoker_type == "thumbnail_button":
return not is_open
else:
return is_open
Lastly the imports:
from dash.dependencies import Input, Output, ALL

Related

Streamlit all buttons are the same

import streamlit as st
import base64
def custom_button(text='button', bgpng=None, height='height: 225px;', width='width: 225px'):
with open (bgpng, 'rb') as img:
convert_img = base64.b64encode(img.read()).decode('utf-8')
background_img = f"background-image: url('data:image/png;base64, {convert_img}');"
st.markdown(f"""
<style>
div.stButton > button:first-child {{
{background_img}
{height}
{width}
}}
</style>""", unsafe_allow_html=True)
button = st.button(text)
return button
button1 = custom_button(text='button', bgpng=r'data\pic1.png')
button2 = custom_button(text='button2', bgpng=r'data\pic2.png')
The problem is the following, the last button always determines the properties of the other buttons, in this case the background image of button2 determines the background image of button1. So all buttons have the same background image. How can i solve it?
You create x styles for x buttons so the last style is applyed since it's the same priority.
I don't use python but I guess you could set an id for your buttons and apply your styles to #{button_id} (or something like that), or apply inline style like below :
<button style="background-color:orange;">button</button>
<button style="background-color:grey;">button2</button>
I found a solution.
If the streamlit code is ready, in the browser, right click, inspect , copy the css selector, then we get the unique button css selector. We need to replace this piece of code:
"div.stButton > button:first-child"
Should be replaced with: "copied css selector"
We have to do it for each button.

Is it possible to get the current position of an ipywidget?

I'm using the ipyvuetfy lib that create nice dashboarding element based ont he vuetify.js lib and ipyvwidgets.
I need to place a dialog in a specific position (on top of another element) like this menu placed on top of a select folder btn.
How can I access the the current position of a widget relative to the window ?
It is possible with Javascript code, by identifying the widget with a custom class and using the jQuery offset() method, and then setting the DOM Style top and left properties of the child (here a Card) of the ipyvuetify Dialog, with the style position set as fixed. I haven't found how to execute the JS code via the Dialog activator slot, so the Dialog widget is triggered via the click.stop event:
import ipyvuetify as v
import ipywidgets as w
from IPython.display import Javascript
out = w.Output(layout={'display': 'none'})
js = '''
var x = $(".myparentwidget").offset();
var d = document.getElementsByClassName("mydialog")[0];
d.style.top = x.top+"px";
d.style.left= x.left+"px";'''
def on_click(widget, event, data):
dialog.v_model=True
with out:
display(Javascript(js, lib="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"))
btn = v.Btn(
children=["Open dialog"],
class_='myparentwidget'
)
btn.on_event("click.stop", on_click)
dialog = v.Dialog(
v_model=False,
children=[
v.Card(
class_='mydialog',
style_="position: fixed; width: 300px",
children=[
v.CardTitle(children=["Dialog window"]),
v.CardText(children=['Dialog text']),
]
)
],
)
v.Layout(children=[btn,dialog,out])

How to use a button in bottle?

I am making a simple currency exchanger with Bottle.
I want to make a submit button so that when I click it, some text will be triggered on the page I am on.
So far I only know how to make a new template so that the button takes me to a new page, but I don't know how to add it to the page I am on.
import bottle
def exchanger():
amount = float(bottle.request.forms["amount"])
currency1 = bottle.request.forms["currency1"]
valuta2 = bottle.request.forms["currency2"]
return bottle.template("result.html",
calculate=calculate,
amount=amount,
currency1=currency1,
currency2=currency2)

Add right-click functionality to listwidget in PyQt4

Im trying to add right-click functionality to items in a list widget in PyQt4 using Python. Id like a pop up context menu to show that has buttons and when clicked should perform some function.
How do I get a context menu to pop up when right clicking on each of the items?
I have come up with a pretty simple way of doing this and works perfectly. In the ControlMainWindow class add the following to initialise the Context menu policy as CustomeContextMenu where listWidget_extractedmeters will be the name of your QListWidget:
self.listWidget_extractedmeters.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.listWidget_extractedmeters.connect(self.listWidget_extractedmeters,QtCore.SIGNAL("customContextMenuRequested(QPoint)" ), self.listItemRightClicked)
Then in the ControlMainwindow class the following functions allow you to add context menu items and to call a funtion that performs some functionality:
def listItemRightClicked(self, QPos):
self.listMenu= QtGui.QMenu()
menu_item = self.listMenu.addAction("Remove Item")
self.connect(menu_item, QtCore.SIGNAL("triggered()"), self.menuItemClicked)
parentPosition = self.listWidget_extractedmeters.mapToGlobal(QtCore.QPoint(0, 0))
self.listMenu.move(parentPosition + QPos)
self.listMenu.show()
def menuItemClicked(self):
currentItemName=str(self.listWidget_extractedmeters.currentItem().text() )
print(currentItemName)

python: Right Click on list menu not showing item selected

In my ongoing effort to learn more about python, I am trying to add a right click event to my mp3 manager program. What currently works is that it shows the menu and all of the options. What is not working is the functions selected from the menu are not executing as I think they should be. Much of this code was taken from a 'how to' on another site.
Here are the right click menu options
menu_titles = ["Remove Selection from list",
"Delete Selection from system",
"Move Selection",
"Copy Selection",
"Print Selection"]
menu_title_by_id = {}
for title in menu_titles:
menu_title_by_id[ wxNewId() ] = title
The code that is run when the right click event happens
def RightClickCb( self, event ):
# record what was clicked
self.list_item_clicked = right_click_context = event.GetText()
### 2. Launcher creates wxMenu. ###
menu = wxMenu()
for (id,title) in menu_title_by_id.items():
### 3. Launcher packs menu with Append. ###
menu.Append( id, title )
### 4. Launcher registers menu handlers with EVT_MENU, on the menu. ###
EVT_MENU( menu, id, self.MenuSelectionCb )
### 5. Launcher displays menu with call to PopupMenu, invoked on the source component, passing event's GetPoint. ###
self.MainPanel.PopupMenu( menu, event.GetPoint() )
menu.Destroy() # destroy to avoid mem leak
def MenuSelectionCb( self, event ):
# do something
operation = menu_title_by_id[ event.GetId() ]
target = self.list_item_clicked
print 'Perform "%(operation)s" on "%(target)s."' % vars()
What I expect to get when I do a right-click and then select one of the options in the menu is the output
Perform "Print Selection" on "<data about the selection here>"
What I am getting is
Perform "Print Selection" on "."
How do I get the data from the item I have selected as part of my right click event?
Maybe you should use event.GetString() in place of event.GetText()
See here
Your code seems outdated tho, binding to events should be done like this:
menu.Bind(wx.EVT_MENU, self.MenuSelectionCb, id=id)
moreover if you bind all ids to the same function you can just bind once for all ids:
menu.Bind(wx.EVT_MENU, self.MenuSelectionCb)
You can find a solution under Python: Right click on objectlistview not showing item name selected where the use of objectlistview's GetSelectedObject() method is proposed instead.

Categories