Problem: I am not able to get an icon image to appear next to the root node in tkinter.ttk.Treeview. Below is a test code I used. It executed w/o errors but image did not appear on the left of root node. I have tried using the full path name of the image file but that did not work. Also, I have tried using PIL.ImageTk.PhotoImage to open the image file but that did not work either. Instead an error as shown below appeared.
Question: How do I get an icon image to appear on the left of the root node (or any node) of tkinter.ttk.Treeview?
Test Code:
import os
import tkinter as tk
import tkinter.ttk as ttk
from PIL import Image, ImageTk
class App(ttk.Frame):
def __init__(self, master, path):
ttk.Frame.__init__(self, master)
self.tree = ttk.Treeview(self)
ysb = ttk.Scrollbar(self, orient='vertical', command=self.tree.yview)
xsb = ttk.Scrollbar(self, orient='horizontal', command=self.tree.xview)
self.tree.configure(yscroll=ysb.set, xscroll=xsb.set)
self.tree.heading('#0', text='Directory', anchor='w')
abspath = os.path.abspath(path)
i = './icon/Home-icon_16.gif'
root_pic = tk.PhotoImage(file=i)
#root_pic = ImageTk.PhotoImage(i)
root_node = self.tree.insert('', 'end', text=abspath, open=True, image=root_pic)
l1_node = self.tree.insert(root_node, 'end', text='level 1', open=True)
l2_node = self.tree.insert(l1_node, 'end', text='level 2', open=True)
l3_node = self.tree.insert(l2_node, 'end', text='level 3', open=True)
l2a_node = self.tree.insert(l1_node, 'end', text='level 2a', open=True)
l3a_node = self.tree.insert(l2a_node, 'end', text='level 3a', open=True)
self.tree.grid(row=0, column=0)
ysb.grid(row=0, column=1, sticky='ns')
xsb.grid(row=1, column=0, sticky='ew')
self.grid()
root = tk.Tk()
path_to_my_project = os.getcwd()
app = App(root, path=path_to_my_project)
app.mainloop()
Error msg from using PIL.ImageTk.PhotoImage:
root_pic = ImageTk.PhotoImage(i)
File "/usr/lib/python3/dist-packages/PIL/ImageTk.py", line 108, in __init__
mode = Image.getmodebase(mode)
File "/usr/lib/python3/dist-packages/PIL/Image.py", line 296, in getmodebase
return ImageMode.getmode(mode).basemode
File "/usr/lib/python3/dist-packages/PIL/ImageMode.py", line 52, in getmode
return _modes[mode]
KeyError: './icon/Home-icon_16.gif'
Home-icon_16.gif:
Applications: python3.5 ver3.5.1-10; python3-tk ver3.5.1-1; tk8.6 ver8.6.5-1; python3-pil.imagetk:amd64 ver3.1.2-0ubuntu1
Try creating PIL image first with Image.open('file_path') and then do Photoimage. Also, you need to keep a reference to the PhotoImage or it wont show in tkinter.
import os
import tkinter as tk
import tkinter.ttk as ttk
from PIL import Image, ImageTk
class App(ttk.Frame):
def __init__(self, master, path):
ttk.Frame.__init__(self, master)
self.tree = ttk.Treeview(self)
ysb = ttk.Scrollbar(self, orient='vertical', command=self.tree.yview)
xsb = ttk.Scrollbar(self, orient='horizontal', command=self.tree.xview)
self.tree.configure(yscroll=ysb.set, xscroll=xsb.set)
self.tree.heading('#0', text='Directory', anchor='w')
abspath = os.path.abspath(path)
i = './icon/Home-icon_16.gif'
root_pic1 = Image.open(i) # Open the image like this first
self.root_pic2 = ImageTk.PhotoImage(root_pic1) # Then with PhotoImage. NOTE: self.root_pic2 = and not root_pic2 =
root_node = self.tree.insert('', 'end', text=abspath, open=True, image=self.root_pic2)
l1_node = self.tree.insert(root_node, 'end', text='level 1', open=True)
l2_node = self.tree.insert(l1_node, 'end', text='level 2', open=True)
l3_node = self.tree.insert(l2_node, 'end', text='level 3', open=True)
l2a_node = self.tree.insert(l1_node, 'end', text='level 2a', open=True)
l3a_node = self.tree.insert(l2a_node, 'end', text='level 3a', open=True)
self.tree.grid(row=0, column=0)
ysb.grid(row=0, column=1, sticky='ns')
xsb.grid(row=1, column=0, sticky='ew')
self.grid()
root = tk.Tk()
path_to_my_project = os.getcwd()
app = App(root, path=path_to_my_project)
app.mainloop()
Related
I am new to plotly dash and i'm trying to make a heatmap that changes with a dropdown selection. The dropdown is to choose a month, but the heatmap doesn't change!
My data frame is called 'New'.
Here's my code:
Month_Default = New['Month'].unique()
Month_def = 2
#create the dash app
app = dash.Dash()
app.layout = html.Div([
html.H1('//Title'),
html.Div([
html.Div([
html.H4('Select Month...'),
dcc.Dropdown(
id='Month_dropdown',
options=[{'label': i, 'value': i} for i in Month_Default],
value = Month_Def
),
],
style={'width': '48%', 'display': 'inline-block'}),
dcc.Graph(id='heatmap',
figure = {
'data': [go.Heatmap(
x=New['Days'].where(New['Month']==2),
y=New['Hour'],
z=New['Usage'],
colorscale='Viridis')],
'layout': go.Layout(
xaxis = dict(title = 'Days'),
yaxis = dict( title = 'Hours'),
)})
]),])
#app.callback(
dash.dependencies.Output(component_id='heatmap',component_property='figure'),
[dash.dependencies.Input(component_id='Month_dropdown',component_property='value')]
)
def update_graph(Month_dropdown):
filtered_df = New[New['Month'] == Month_dropdown]
heat_fig = go.Heatmap(filtered_df,
x='Days', y='Hour', z='Usage',
colorscale='Viridis',
title='PM KWH Usage')
return heat_fig
have created New dataframe in the way you described it in comments
using dash 2.0.0 hence only need to import dash
two key steps missed
did not app.run_server() to start the dash app
no callback to respond to Dropdown
instead of repeating code in dash layout and callback moved figure creation to just the callback
import dash
from jupyter_dash import JupyterDash
import plotly.graph_objects as go
from dash.dependencies import Input, Output, State
import pandas as pd
import numpy as np
New = pd.DataFrame(
{"date": pd.date_range("1-jan-2021", "15-jun-2021", freq="H")}
).assign(
Usage=lambda d: np.random.uniform(0, 1, len(d)),
Month=lambda d: d["date"].dt.month,
Days=lambda d: d["date"].dt.day,
Hour=lambda d: d["date"].dt.hour,
)
Month_Default = New["Month"].unique()
Month_def = 2
# create the dash app
# app = dash.Dash()
app = JupyterDash(__name__)
app.layout = dash.html.Div(
[
dash.html.H1("//Title"),
dash.html.Div(
[
dash.html.Div(
[
dash.html.H4("Select Month..."),
dash.dcc.Dropdown(
id="Month_dropdown",
options=[{"label": i, "value": i} for i in Month_Default],
value=Month_def,
),
],
style={"width": "48%", "display": "inline-block"},
),
dash.dcc.Graph(id="heatmap"),
]
),
]
)
#app.callback(Output("heatmap", "figure"), Input("Month_dropdown", "value"))
def updateGraph(value):
if not value:
value = Month_def
return {
"data": [
go.Heatmap(
x=New["Days"].where(New["Month"] == value),
y=New["Hour"],
z=New["Usage"],
colorscale="Viridis",
)
],
"layout": go.Layout(
xaxis=dict(title="Days"),
yaxis=dict(title="Hours"),
margin={"l": 0, "r": 0, "t": 0, "b": 0},
),
}
app.run_server(mode="inline")
In my app, when I press that PlateButton, the wx.EVT_KEY_DOWN stop working. I don't know what's going on. If I erase the bmpImage code and set the parent of the PlateButton to self, the event doesn't even fire in the first place.
Thanks!
import wx
import wx.lib.platebtn as pb
class MainFrame(wx.Frame):
def __init__(self, parent):
super().__init__(parent)
self.initUI()
self.Bind(wx.EVT_KEY_DOWN, self.OnKey)
def initUI(self):
bmpImage = wx.StaticBitmap(self, wx.ID_ANY)
bmpImage.SetBitmap(wx.Bitmap('image.JPG', wx.BITMAP_TYPE_ANY))
btn = pb.PlateButton(bmpImage, -1, 'Click Me!', style=pb.PB_STYLE_NOBG)
def OnKey(self, event):
print('Key pressed!')
event.Skip()
app = wx.App()
frame = MainFrame(None)
frame.Show()
app.MainLoop()
If you run the following code, you'll see that the platebutton is grabbing the event and obviously not skipping the event, thus it is not available to the frame, which you are binding to.
import wx
import wx.lib.platebtn as pb
class MainFrame(wx.Frame):
def __init__(self, parent):
super().__init__(parent)
self.initUI()
self.Bind(wx.EVT_KEY_DOWN, self.OnKey)
def initUI(self):
text = wx.StaticText(self, -1, "Key Test", pos=(10, 10))
btn = pb.PlateButton(self, -1, 'Click Me!', pos=(10,40), size=(100,25))
btn.Bind(wx.EVT_KEY_DOWN, self.OnKey)
def OnKey(self, event):
print(event.GetEventObject())
print('Key pressed!')
event.Skip()
app = wx.App()
frame = MainFrame(None)
frame.Show()
app.MainLoop()
Is there a function or option that adds an image in PushButton widget? In this situation, The added image means an image as a background applied to the entire widget, not an image as an 'icon'. I tried to find this option and I use the 'setStyleSheet' function, but it doesn't work. What is a problem, and how can I add an image in pushbutton?
btn6.setStyleSheet(
"color: black;"
"border-style: solid;"
"border-width: 2px;"
"border-color: #FFB400;"
"border-radius: 3px;"
"background-color: #FFD732;"
"**background-image: url('D:\PyQt5_Tutorial\Test.png')")**
You can just override QPushButton.paintEvent() for this. And dont forget to add interactivity to reflect different states of button: sunken, disabled, mouse hover, input focus.
from PyQt5 import QtWidgets, QtGui
class Button(QtWidgets.QPushButton):
def __init__(self, parent = None) -> None:
super().__init__(parent)
self._image = None
def setImage(self, image):
self._image = image
self.update()
class Button(QtWidgets.QPushButton):
def __init__(self, parent = None) -> None:
super().__init__(parent)
self._image = None
def setImage(self, image):
self._image = image
self.update()
def paintEvent(self, event):
if self._image is None:
return
opt = QtWidgets.QStyleOptionButton()
self.initStyleOption(opt)
rect = self.rect()
painter = QtGui.QPainter(self)
self.style().drawControl(QtWidgets.QStyle.CE_PushButtonBevel, opt, painter, self)
if opt.state & QtWidgets.QStyle.State_Sunken:
rect.adjust(2,2,2,2)
painter.drawImage(rect, self._image)
if opt.state & QtWidgets.QStyle.State_MouseOver:
color = self.palette().color(QtGui.QPalette.Highlight)
color.setAlpha(50)
painter.fillRect(self.rect(), color)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
button = Button()
button.setImage(QtGui.QImage("D:\\PyQt5_Tutorial\\Test.png"))
button.show()
app.exec()
The docking is created as required. What I'm not able to do is creating 'Shelf' widget above docking.
It shouldn't be part of docking and it should remain at the top. When hidden, docks should cover up the
space and when shown again docks should move below.
import sys
from PySide2 import QtGui, QtCore, QtWidgets
class Shelf(QtWidgets.QTabWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.tab1 = QtWidgets.QWidget()
self.tab2 = QtWidgets.QWidget()
self.tab3 = QtWidgets.QWidget()
self.addTab(self.tab1, "Tab 1")
self.addTab(self.tab2, "Tab 2")
self.addTab(self.tab3, "Tab 3")
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.centre = QtWidgets.QMainWindow(self)
self.centre.setWindowFlags(QtCore.Qt.Widget)
self.centre.setDockOptions(
QtWidgets.QMainWindow.AnimatedDocks |
QtWidgets.QMainWindow.AllowNestedDocks)
self.setCentralWidget(self.centre)
self.dockCentre1 = QtWidgets.QDockWidget(self.centre)
self.dockCentre1.setWindowTitle('Centre 1')
self.centre.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dockCentre1)
self.dockCentre2 = QtWidgets.QDockWidget(self.centre)
self.dockCentre2.setWindowTitle('Centre 2')
self.centre.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dockCentre2)
self.dockLeft = QtWidgets.QDockWidget(self)
self.dockLeft.setWindowTitle('Left')
self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dockLeft)
self.dockLeft1 = QtWidgets.QDockWidget(self)
self.dockLeft1.setWindowTitle('Left')
self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dockLeft1)
self.dockRight = QtWidgets.QDockWidget(self)
self.dockRight.setWindowTitle('Right')
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dockRight)
self.dockRight1 = QtWidgets.QDockWidget(self)
self.dockRight1.setWindowTitle('Right')
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dockRight1)
self.menuBar().addMenu('File').addAction('Quit', self.close)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.setGeometry(500, 50, 600, 400)
window.show()
sys.exit(app.exec_())
I'm extremely new to Pygtk and Stackoverflow in general. I'm trying to build a small dictionary application: I have one master VBox and an Hbox containing two Vboxes divided by a Vseparator. I am trying to display text through a label in the right-hand Vbox, but it will not appear. Here's my pitiful code:
import gtk
import pygtk
from Wordlist import *
pygtk.require('2.0')
def click_handler(button):
for i in nouns:
print i
k = gtk.Label(str=i)
k.show()
meaningvbox.pack_start(k,True,True,0)
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_size_request(300,400)
window.set_title("English-Japanese Reference")
window.show()
window.connect("delete-event", gtk.main_quit)
vbox = gtk.VBox(False,0)
window.add(vbox)
vbox.show()
hbox = gtk.HBox(True,0)
vbox.pack_end(hbox,False)
hbox.show()
hbox2 = gtk.HBox(True,0)
vbox.pack_end(hbox2,False)
hbox2.show()
vsep = gtk.VSeparator()
vbox.pack_start(vsep)
vsep.show()
dichbox = gtk.HBox() #### These are boxes created to store the words
vbox.pack_start(dichbox)
wordvbox = gtk.VBox()
dichbox.pack_start(wordvbox)
wordvbox.show()
meaningvbox = gtk.VBox()
dichbox.pack_start(meaningvbox)
meaningvbox.show()
label = gtk.Label(str="hi")
meaningvbox.pack_start(label)
label.show()
verbButton = gtk.Button(label="Verbs")
hbox.pack_end(verbButton,True,False)
verbButton.set_size_request(100,30)
verbButton.show()
nounButton = gtk.Button(label="Nouns")
nounButton.set_size_request(100,30)
hbox.pack_end(nounButton,True,False)
nounButton.show()
nounButton.connect("clicked", click_handler)
familyButton = gtk.Button(label="Family")
familyButton.set_size_request(100,30)
hbox.pack_end(familyButton,True,False)
familyButton.show()
particleButton = gtk.Button(label="Particles")
hbox2.pack_end(particleButton,True,False)
particleButton.set_size_request(100,30)
particleButton.show()
adjectiveButton = gtk.Button(label="Adjectives")
adjectiveButton.set_size_request(100,30)
hbox2.pack_end(adjectiveButton,True,False)
adjectiveButton.show()
pronounButton = gtk.Button(label="Pronouns")
pronounButton.set_size_request(100,30)
hbox2.pack_end(pronounButton,True,False)
pronounButton.show()
def main():
gtk.mainloop()
main()
You forgot to call dichbox.show().
I would also recommend to restructure your code and group similar function calls, use show_all() instead of many show()s and use a class for the whole window.
That's what it would look like:
import pygtk
pygtk.require('2.0')
import gtk
from Wordlist import *
class Window(gtk.Window):
def __init__(self):
gtk.Window.__init__(self,gtk.WINDOW_TOPLEVEL)
self.set_size_request(300,400)
self.set_title("English-Japanese Reference")
self.connect("delete-event", gtk.main_quit)
verbButton = gtk.Button(label="Verbs")
nounButton = gtk.Button(label="Nouns")
nounButton.connect("clicked", self.click_handler)
familyButton = gtk.Button(label="Family")
particleButton = gtk.Button(label="Particles")
adjectiveButton = gtk.Button(label="Adjectives")
pronounButton = gtk.Button(label="Pronouns")
verbButton.set_size_request(100,30)
nounButton.set_size_request(100,30)
familyButton.set_size_request(100,30)
particleButton.set_size_request(100,30)
adjectiveButton.set_size_request(100,30)
pronounButton.set_size_request(100,30)
hbox = gtk.HBox(True,0)
hbox.pack_end(verbButton, True, False)
hbox.pack_end(nounButton, True, False)
hbox.pack_end(familyButton, True, False)
hbox2 = gtk.HBox(True,0)
hbox2.pack_end(particleButton, True, False)
hbox2.pack_end(adjectiveButton, True, False)
hbox2.pack_end(pronounButton, True, False)
label = gtk.Label("hi")
self.meaningvbox = gtk.VBox()
self.meaningvbox.pack_start(label)
wordvbox = gtk.VBox()
vsep = gtk.VSeparator()
dichbox = gtk.HBox()
dichbox.pack_start(wordvbox)
dichbox.pack_start(vsep)
dichbox.pack_start(self.meaningvbox)
vbox = gtk.VBox(False, 0)
vbox.pack_end(hbox, False)
vbox.pack_end(hbox2, False)
vbox.pack_start(dichbox)
self.add(vbox)
self.show_all()
def click_handler(self,button):
for i in nouns:
k = gtk.Label(i)
k.show()
self.meaningvbox.pack_start(k, True, True, 0)
def main():
win = Window()
gtk.main()
main()