【问题标题】:Removing selected items from the listbox and from the list从列表框和列表中删除选定的项目
【发布时间】:2017-04-13 17:00:03
【问题描述】:

我有一个用 C# 编写的应用程序需要转换为 Python,因为我最近切换到了 Linux。这是一个简单的 GUI 应用程序,用于在学习新语言的同时管理未知单词。不过,我需要 remove_item() 函数,我还需要 find_word() 函数。

在 C# 中,我将创建以下两个方法:

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);
}

...但是在 Python 方面我仍然是新手,因此我们将不胜感激。这是我目前所拥有的:

对于 FindWord() 方法,可以改写如下:

def FindWord(word):
    for x in words:
        if x.WordOrPhrase == word:
            return x

def FindWord(word):
    return next((x for x in words if x.WordOrPhrase == word), None)

def FindWord(word):
    return next(filter(lambda x: x.WordOrPhrase == word, words), None)

...但我正在努力重写 Remove() 方法。这是一种方法:

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)

...我最想要的是将我的 C# 方法转换为 Python。这是我目前所拥有的:

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

我不知道如何访问:

  • listView1.SelectedItems[0].Text
  • listView1.SelectedItems.Count > 0
  • listView1.SelectedItems
  • listView1.Items[listView1.Items.Count - 1].Selected

这是我到目前为止所做的:

# 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()

【问题讨论】:

  • 迁移到 Linux 不会迫使您放弃 C#。有适用于 Linux 的 C# 编译器和开发环境。
  • 是的,但我需要 Python 上大学,所以我正在练习......
  • 您是否学习过任何教程或阅读过有关使用列表框的任何文档。所有方法都有据可查。
  • 我现在。只是想问一个问题:“listView1.SelectedItems.Count > 0 的 Python 等价物是什么,是curselection()
  • @wraith1337 len(curselection()) = SelectedItems.Count。我在下面发布了我的一般删除方法作为答案。

标签: c# python list tkinter listbox


【解决方案1】:

对于我的列表框,我通常将模式设置为EXTENDED,以便用户可以选择一个或多个项目并一次删除所有项目。我通过以下方法这样做:

# 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

例如,假设在我的列表框中我有 4 个项目。然后我选择第一项和第三项。通过致电list_box.curselection(),我收到了以下信息:

selected_items = (0, 2)

其中0 是列表框中第一项的位置,2 是第三项的位置。然后对于我的元组中的每个项目,我建立它的索引。

遍历此,对于第一项,发生以下情况:

idx = 0 - 0
list_box.delete(0, 0)
pos = 1

所以现在我删除了位置0 的项目(例如第一个项目)并且我的列表框已经移动!所以第二个现在是第一个,第三个是第二个,第四个是第三个。但是,我的元组 没有改变,因为它是 original 选择的列表框中的位置。这是关键。接下来发生的事情是:

idx = 2 - 1
list_box.delete(1, 1)
pos = 2

由于列表框移动,位置1 现在对应于最初位于列表框第三位置的项目。对于n 职位,这可以继续。

用于删除 self.words

您可以尝试以下方法:

# 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

【讨论】:

  • 我明白了,但是同时从列表中删除项目呢?我将编辑我的问题,看看它:
  • @wraith1337 这会立即从列表框中删除所有选定的项目。我只是将其分解为向您展示该过程的工作原理。使用我的答案,您选择n 列表框中的项目数,它会立即将它们全部删除。它是安全的,因为它不会更改任何剩余项目的顺序并将它们的位置移动到列表框的顶部。
  • 你不懂,我得把它们从列表框和列表中删除。
  • @wraith1337 有问题的列表是list = [ ] 对象还是另一个列表框?在您问题的最后一个代码示例中,除了您尝试使用.remove() 的列表框之外,我没有看到任何其他需要删除方法的对象。
  • 是的,我有一个列表框和一个列表 (self.words = [ ])。我将包含我的整个代码,以便您可以看到我在说什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-18
  • 1970-01-01
相关资源
最近更新 更多