我有一个显示上下文菜单的 TreeView。菜单按原样显示。
但我不确定如何确定 a) 是否显示弹出窗口,和/或 b) 获取所选值。
我不关心哪个项目激活了弹出窗口,因为根据弹出窗口值采取的操作将关闭窗口,启动新查询并显示新数据。
class ListingWin(Gtk.Window):
torrent_list_store: ListStore
def __init__(self, torrent_list, engine_key):
self.torrent_list = torrent_list
self.engine = engine_key
Gtk.Window.__init__(self, title="Torrent Listing - " + SUPPORTED_ENGINES[self.engine])
self.connect('delete-event', self.on_destroy)
self.entry = Gtk.Entry()
self.entry.connect("activate", self.submit) # enables enter key
self.set_border_width(10)
self.set_default_size(1000, 400)
self.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
# Setting up the grid in which the elements are to be positioned
self.grid = Gtk.Grid()
self.grid.set_column_homogeneous(True)
self.grid.set_row_homogeneous(True)
self.add(self.grid)
# Post-process torrent_list: Create dictionary (fields 1,5) for magnet[title] lookup
titles, magnets = [], []
for L in self.torrent_list:
titles.append(L[0])
magnets.append(L[-1])
# Stash the magnets
self.magnet_dict = dict(zip(titles, magnets))
# Post-process torrent_list: Create listStore (fields 1-5) without magnets
post_list = np.array(self.torrent_list)
store_data = post_list[:, :5].tolist() # numpy syntax for grabbing fields 1-5 from each row
# Create the ListStore model: "Title", "Date", "Seeds", "Leeches", "Size"
self.torrent_list_store = Gtk.ListStore(str, str, int, int, str, float)
for torrent_ref in store_data:
f1 = torrent_ref[0] # title
f2 = torrent_ref[1] # Date
f3 = int(torrent_ref[2]) # Seeds
f4 = int(torrent_ref[3]) # Leeches
f5 = torrent_ref[4] # Size
# sort MB, GB, and KiB
if "N/A" in f5:
s5 = 0
elif "G" in f5:
c5 = f5.replace('G', '')
n1 = float(c5)
n2 = float(1024)
s5 = n1 * n2
elif "M" in f5:
c5 = f5.replace('M', '')
s5 = float(c5)
elif "K" in f5:
c5 = f5.replace('KiB', '')
s5 = float(c5)
else:
s5 = re.sub('[^0-9\.]', '', f5)
row = [f1, f2, f3, f4, f5, s5]
self.torrent_list_store.append(row)
# Create the treeview; pass the model
self.treeview = Gtk.TreeView()
self.treeview.set_model(self.torrent_list_store)
# Add columns & headers
renderer_1 = Gtk.CellRendererText()
renderer_2 = Gtk.CellRendererText()
renderer_2.set_property("xalign", 1)
column = Gtk.TreeViewColumn("Title", renderer_1, text=0)
column.set_sort_column_id(0)
self.treeview.append_column(column)
column = Gtk.TreeViewColumn("Date", renderer_2, text=1)
column.set_sort_column_id(1)
self.treeview.append_column(column)
column = Gtk.TreeViewColumn("Seeds", renderer_2, text=2)
column.set_sort_column_id(2)
self.treeview.append_column(column)
column = Gtk.TreeViewColumn("Leeches", renderer_2, text=3)
column.set_sort_column_id(3)
self.treeview.append_column(column)
# Display field for Size (f4), sort field for Size (s5)
column = Gtk.TreeViewColumn("Size", renderer_2, text=4)
column.set_sort_column_id(5)
self.treeview.append_column(column)
# Define the buttons
self.buttons = list()
button = Gtk.Button(label="Download")
button.connect("clicked", self.on_download)
self.buttons.append(button)
button = Gtk.Button(label="Search")
button.connect("clicked", self.on_close)
self.buttons.append(button)
button = Gtk.Button(label="Quit")
button.connect("clicked", self.on_quit)
self.buttons.append(button)
# Alternate engine context menu
self.treeview.connect("button_press_event", self.show_context_menu)
# Capture double click on row
self.treeview.connect("row-activated", self.row_active)
# Set multiple rows option
self.treeview.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
# Set up the layout, put the treeview in a scroll window and add the buttons in a row
self.scrollable_treeList = Gtk.ScrolledWindow()
self.scrollable_treeList.set_vexpand(True)
self.grid.attach(self.scrollable_treeList, 0, 0, 8, 10) # row,col,(h,w cells)
self.grid.attach_next_to(self.buttons[0], self.scrollable_treeList, Gtk.PositionType.BOTTOM, 1, 1)
for i, button in enumerate(self.buttons[1:]):
self.grid.attach_next_to(button, self.buttons[i], Gtk.PositionType.RIGHT, 1, 1)
self.scrollable_treeList.add(self.treeview)
# Context menu to select another engine
def show_context_menu(self, widget, event):
if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3:
context_menu = Gtk.Menu()
for key, value in SUPPORTED_ENGINES.items():
if key == self.engine:
continue
cm_item = Gtk.MenuItem(label=value)
context_menu.add(cm_item)
context_menu.attach_to_widget(self, None)
context_menu.show_all()
context_menu.popup(None, None, None, None, event.button, event.time)
# If double-click on row, download and exit
def row_active(self, tv, col, tv_col):
self.on_download(self)
self.on_quit(self)
def on_download(self, button):
# Retrieve selected titles from ListStore
selected_titles = []
selection = self.treeview.get_selection()
(self.torrent_list_store, tree_iterator) = selection.get_selected_rows()
for path in tree_iterator:
path_iter = self.torrent_list_store.get_iter(path)
if path_iter is not None:
selected_titles.append(
self.torrent_list_store.get_value(path_iter, 0))
# Pass selected magnets to torrent client and exit
for title in selected_titles:
subprocess.Popen([TORRENT_CLIENT, self.magnet_dict[title]],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
self.on_quit(self)
def submit(self, entry):
self.destroy()
Gtk.main_quit()
def on_close(self, button):
self.destroy()
Gtk.main_quit()
def on_destroy(self, dummy, args):
self.destroy()
sys.exit(0)
def on_quit(self, button):
self.destroy()
sys.exit(0)
def filter_sz_age(tag):
if tag.find('a') is not None: # eliminate <td containing <a tags
return False
return tag.name == 'td' and len(tag.attrs) == 2 and (
tag.attrs["class"] == ["forum_thread_post"] and tag.attrs["align"] == 'center')