问题
I have an application written in C# that needs to be converted to Python, since I have recently switched to Linux. It's a simple GUI application to manage unknown words while learning a new language. Nevertheless, I need remove_item() function for which I also need find_word() function.
In C#, I would create two following methods:
void Remove()
{
Word word = new Word();
try { word = FindWord(listView1.SelectedItems[0].Text); }
catch { return; }
if (listView1.SelectedItems.Count > 0)
{
try
{
foreach (ListViewItem eachItem in listView1.SelectedItems)
{
words.RemoveAll(x => x.WordOrPhrase == eachItem.Text);
listView1.Items[listView1.Items.Count - 1].Selected = true;
listView1.Items.Remove(eachItem);
}
}
catch { }
ClearAll();
ReadOnlyON();
}
else
{
MessageBox.Show("You have not selected any words!", "Notification", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
ReadOnlyOFF();
WordCount();
Sync();
}
private Word FindWord(string word)
{
return words.Find(x => x.WordOrPhrase == word);
}
...but I'm still a newbie when it comes to Python, so any help would be appreciated. Here is what I have so far:
When it comes to the FindWord() method, it could be rewritten as following:
def FindWord(word):
for x in words:
if x.WordOrPhrase == word:
return x
or
def FindWord(word):
return next((x for x in words if x.WordOrPhrase == word), None)
or
def FindWord(word):
return next(filter(lambda x: x.WordOrPhrase == word, words), None)
...but I'm struggling to rewrite Remove() method. Here is one way:
def remove_item(self):
word = self.listBox.get(ACTIVE)
new_word_list = [] # initialize empty list
delete_idxs = []
for idx, item in enumerate(self.words):
if item.wordorphrase == word:
delete_idxs.append(idx)
else:
new_word_list.append(item)
self.words = new_word_list # overwrite the old word_list with the new one
for idx in reversed(delete_idxs):
self.listBox.delete(idx)
...what I would like most is converting my C# method to Python. Here is what I have so far:
def remove_item(self):
word = Word()
try:
word = find_word(self.listBox.curselection())
except:
return
if self.listBox.len(curselection()) > 0:
try:
for item in self.listBox.curselection():
self.words.remove(lambda x: x.wordorphrase == item.text)
# listView1.Items[listView1.Items.Count - 1].Selected = true;
self.listBox.remove(item)
except:
pass
self.clear_all()
else:
pass
# show messagebox
I don't know how to access:
listView1.SelectedItems[0].Text
listView1.SelectedItems.Count > 0
listView1.SelectedItems
listView1.Items[listView1.Items.Count - 1].Selected
Here is what I have done so far:
# Vocabulary.py
# GUI program to manage unknown words
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
import xml.etree.ElementTree as ET
import os
class Word:
def __init__(self, wordorphrase, explanation, translation, example):
self.wordorphrase = wordorphrase
self.explanation = explanation
self.example = example
self.translation = translation
class Vocabulary(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.master = master
self.master.resizable(width = False, height = False)
self.master.title("Vocabulary")
self.create_widgets()
self.words = []
self.load_words()
def on_closing(self):
self.save_all()
if messagebox.askokcancel("Quit", "Do you want to quit?"):
self.master.destroy()
def create_widgets(self):
self.buttons_frame = Frame(self.master)
self.buttons_frame.grid(row = 10, sticky = W)
self.search_frame = Frame(self.master)
self.search_frame.grid(row = 1, sticky = W, columnspan = 2)
self.comboBox = ttk.Combobox(self.search_frame,
width = 3)
self.comboBox.grid(row = 0, column = 14, sticky = W)
self.comboBox['values'] = ( 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' )
self.btn_Add = Button(self.buttons_frame,
text = 'Add',
command = self.add_item)
self.btn_Add.grid(row = 0, sticky = W)
self.btn_Remove = Button(self.buttons_frame,
text = 'Remove',
command = self.remove_item)
self.btn_Remove.grid(row = 0, column = 1, sticky = W)
self.btn_Edit = Button(self.buttons_frame,
text = 'Edit',
command = self.edit_item)
self.btn_Edit.grid(row = 0, column = 2, sticky = W)
self.btn_Save = Button(self.buttons_frame,
text = 'Save',
command = self.save_item)
self.btn_Save.grid(row = 0, column = 3, sticky = W)
self.btn_Refresh = Button(self.buttons_frame,
text = 'Refresh',
command = self.refresh_all)
self.btn_Refresh.grid(row = 0, column = 4, sticky = W)
self.lblSearch = Label(self.search_frame, text = 'SEARCH: ')
self.lblSearch.grid(row = 0, column = 5, sticky = W)
self.txt_Search = Text(self.search_frame,
height = 1,
width = 70)
self.txt_Search.grid(row = 0, column = 6, columnspan = 3, sticky = W)
self.lblWordsOrPhrases = Label(self.master, text = 'WORDS/PHRASES:')
self.lblWordsOrPhrases.grid(row = 2, column = 0)
self.lblWordOrPhrase = Label(self.master, text = 'Word or phrase:')
self.lblWordOrPhrase.grid(row = 2, column = 1, sticky = W)
self.listBox = Listbox(self.master,
selectmode='extended',
height = 34,
width = 38)
self.listBox.grid(row = 3, column = 0, rowspan = 7, sticky = W)
self.txt_WordOrPhrase = Text(self.master,
height = 1,
width = 40)
self.txt_WordOrPhrase.grid(row = 3, column = 1, sticky = N)
self.lblExplanation = Label(self.master, text = 'Explanation:')
self.lblExplanation.grid(row = 4, column = 1, sticky = W)
self.txt_Explanation = Text(self.master,
height = 10,
width = 40)
self.txt_Explanation.grid(row = 5, column = 1, sticky = N)
self.lblTranslation = Label(self.master, text = 'Translation:')
self.lblTranslation.grid(row = 6, column = 1, sticky = W)
self.txt_Translation = Text(self.master,
height = 10,
width = 40)
self.txt_Translation.grid(row = 7, column = 1, sticky = N)
self.lblExamples = Label(self.master, text = 'Example(s):')
self.lblExamples.grid(row = 8, column = 1, sticky = W)
self.txt_Example = Text(self.master,
height = 10,
width = 40)
self.txt_Example.grid(row = 9, column = 1, sticky = S)
def load_words(self):
self.listBox.delete(0, END)
self.words.clear()
path = os.path.expanduser('~/Desktop')
vocabulary = os.path.join(path, 'Vocabulary', 'Words.xml')
if not os.path.exists(vocabulary):
if not os.path.exists(os.path.dirname(vocabulary)):
os.mkdir(os.path.dirname(vocabulary))
doc = ET.Element('Words')
tree = ET.ElementTree(doc)
tree.write(vocabulary)
else:
tree = ET.ElementTree(file=vocabulary)
for node in tree.findall('WordOrPhrase'):
w = Word(node.find('Word').text, node.find('Explanation').text, node.find('Translation').text,
node.find('Examples').text)
self.words.append(w)
self.listBox.insert(END, w.wordorphrase)
def save_all(self):
path = os.path.expanduser('~/Desktop')
vocabulary = os.path.join(path, 'Vocabulary', 'Words.xml')
tree = ET.ElementTree(file=vocabulary)
for xNode in tree.getroot().findall('WordOrPhrase'):
tree.getroot().remove(xNode)
for w in self.words:
xTop = ET.Element('WordOrPhrase')
xWord = ET.Element('Word')
xExplanation = ET.Element('Explanation')
xTranslation = ET.Element('Translation')
xExamples = ET.Element('Examples')
xWord.text = w.wordorphrase
xExplanation.text = w.explanation
xTranslation.text = w.translation
xExamples.text = w.example
xTop.append(xWord)
xTop.append(xExplanation)
xTop.append(xTranslation)
xTop.append(xExamples)
tree.getroot().append(xTop)
tree.write(vocabulary)
def add_item(self):
w = Word(self.get_word(), self.get_explanation(), self.get_translation(), self.get_example())
self.words.append(w)
self.listBox.insert(END, w.wordorphrase)
self.clear_all()
self.save_all()
def remove_item(self):
word = Word()
try:
word = find_word(self.listBox.curselection())
except:
return
if self.listBox.len(curselection()) > 0:
try:
for item in self.listBox.curselection():
self.words.remove(lambda x: x.wordorphrase == item.text)
# listView1.Items[listView1.Items.Count - 1].Selected = true;
self.listBox.remove(item)
except:
pass
self.clear_all()
else:
pass
# show messagebox
def edit_item(self):
pass
def save_item(self):
pass
def clear_all(self):
self.txt_WordOrPhrase.delete('1.0', END)
self.txt_Explanation.delete('1.0', END)
self.txt_Translation.delete('1.0', END)
self.txt_Example.delete('1.0', END)
def refresh_all(self):
pass
def get_word(self):
return self.txt_WordOrPhrase.get('1.0', '1.0 lineend')
def get_explanation(self):
return self.txt_Explanation.get('1.0', '1.0 lineend')
def get_translation(self):
return self.txt_Translation.get('1.0', '1.0 lineend')
def get_example(self):
return self.txt_Example.get('1.0', '1.0 lineend')
def find_word(word):
for x in self.words:
if x.wordorphrase == word:
return x
def main():
root = Tk()
gui = Vocabulary(root)
root.protocol('WM_DELETE_WINDOW', gui.on_closing)
root.mainloop()
if __name__ == '__main__':
main()
回答1:
For my listboxes, I generally have the mode set to EXTENDED
so that users can select one or more items and remove all at once. I do so via the following method:
# Function with Tk.Listbox passed as arg
def remove_from(list_box):
# Tuple of currently selected items in arg
selected_items = list_box.curselection()
# Initialize a 'repositioning' variable
pos = 0
for item in selected_items:
# Set index of each item selected
idx = int(item) - pos
# Deletes only that index in the listbox
list_box.delete(idx, idx)
# Increments to account for shifts
pos += 1
For example, lets say in my listbox I had 4 items. I then select the first item and the third item. By calling list_box.curselection()
I've received the following:
selected_items = (0, 2)
Where 0
is the first item's position in the listbox, and 2
is the third item's position. Then for each item in my tuple, I establish its index.
Walking through this, for the first item the following takes place:
idx = 0 - 0
list_box.delete(0, 0)
pos = 1
So now I have deleted the item at position 0
(e.g. the first item) and my listbox has shifted! So the second is now the first, third is the second and fourth is the third. However, my tuple has not changed as it was the positions in the listbox of the original selection. This is key. What happens next is:
idx = 2 - 1
list_box.delete(1, 1)
pos = 2
Since the listbox shifted, position 1
now corresponds to the item that was originally in the third position of the listbox. This can continue for n
positions.
For self.words removal
You could try the following:
# Function with Tk.Listbox and self.words[] passed as args
def remove_from(list_box, list):
# Tuple of currently selected items in arg
selected_items = list_box.curselection()
# List of Words already constructed
word_list = list
# Initialize a 'repositioning' variable
pos = 0
for item in selected_items:
# Set index of each item selected
idx = int(item) - pos
# Deletes only that index in the listbox
list_box.delete(idx, idx)
# Gets the string value of the given index
word = list_box.get(idx, idx)
# Removes the word from the list
if any(word in x for x in word_list):
word_list.remove(word)
# Increments to account for shifts
pos += 1
来源:https://stackoverflow.com/questions/43397908/removing-selected-items-from-the-listbox-and-from-the-list