Как добавить строки виджетов после удаления в QGridLayout

Я добавляю ряды виджетов в QGridLayout вот так (с помощью кнопки):

def ajouter_un_mot_vocab(self) :
    '''
    '''

    # Dictionnaire des mots de vocabulaire    
    self.dico_vocab_mot = {}
    # Dictionnaire des définitions des mots de vocabulaire
    self.dico_vocab_def = {}

    # Liste pour chargement des données 
    # (écriture des textes par l'utilisateur)
    self.liste_mots_vocabulaire = []

    print
    print 'self.grille
def supprimer_un_mot_vocab(self) :
    '''
    '''
    index = len(self.liste_mots_vocabulaire)-1
    for r in reversed(range(self.grille_3_stack_3.rowCount())) :
        for c in reversed(range(self.grille_3_stack_3.columnCount())) 
            layout = self.grille_3_stack_3.itemAtPosition(r, c)
            if layout is not None :
                layout.widget().deleteLater()
                #layout_1.widget().hide()
                self.grille_3_stack_3.removeItem(layout)

    self.liste_mots_vocabulaire.pop() 
    del self.dico_vocab_mot[index] 
    del self.dico_vocab_def[index] 

    print
    print "rowCount apres suppr", self.grille_3_stack_3.rowCount()

    print
    print self.dico_vocab_mot
    print self.dico_vocab_def
    print self.liste_mots_vocabulaire
    print
stack_3.rowCount() creation', self.grille
def supprimer_un_mot_vocab(self) :
    '''
    '''
    index = len(self.liste_mots_vocabulaire)-1
    for r in reversed(range(self.grille_3_stack_3.rowCount())) :
        for c in reversed(range(self.grille_3_stack_3.columnCount())) 
            layout = self.grille_3_stack_3.itemAtPosition(r, c)
            if layout is not None :
                layout.widget().deleteLater()
                #layout_1.widget().hide()
                self.grille_3_stack_3.removeItem(layout)

    self.liste_mots_vocabulaire.pop() 
    del self.dico_vocab_mot[index] 
    del self.dico_vocab_def[index] 

    print
    print "rowCount apres suppr", self.grille_3_stack_3.rowCount()

    print
    print self.dico_vocab_mot
    print self.dico_vocab_def
    print self.liste_mots_vocabulaire
    print
stack_3.rowCount() print # for r in range(self.grille
def supprimer_un_mot_vocab(self) :
    '''
    '''
    index = len(self.liste_mots_vocabulaire)-1
    for r in reversed(range(self.grille_3_stack_3.rowCount())) :
        for c in reversed(range(self.grille_3_stack_3.columnCount())) 
            layout = self.grille_3_stack_3.itemAtPosition(r, c)
            if layout is not None :
                layout.widget().deleteLater()
                #layout_1.widget().hide()
                self.grille_3_stack_3.removeItem(layout)

    self.liste_mots_vocabulaire.pop() 
    del self.dico_vocab_mot[index] 
    del self.dico_vocab_def[index] 

    print
    print "rowCount apres suppr", self.grille_3_stack_3.rowCount()

    print
    print self.dico_vocab_mot
    print self.dico_vocab_def
    print self.liste_mots_vocabulaire
    print
stack_3.rowCount()) : # Création des widgets et taille générique self.dico_vocab_mot[r] = QTextEdit() self.dico_vocab_def[r] = QTextEdit() self.dico_vocab_mot[r].setMaximumWidth(180) self.dico_vocab_mot[r].setMinimumWidth(180) self.dico_vocab_mot[r].setMaximumHeight(54) self.dico_vocab_mot[r].setMinimumHeight(54) self.dico_vocab_def[r].setMaximumHeight(54) self.dico_vocab_def[r].setMinimumHeight(54) print 'r', r # Conditions de redimensionnement if r > 5 : self.dico_vocab_mot[r].setMaximumHeight(34) self.dico_vocab_mot[r].setMinimumHeight(34) self.dico_vocab_def[r].setMaximumHeight(34) self.dico_vocab_def[r].setMinimumHeight(34) # Répartition dans la grille self.grille
def supprimer_un_mot_vocab(self) :
    '''
    '''
    index = len(self.liste_mots_vocabulaire)-1
    for r in reversed(range(self.grille_3_stack_3.rowCount())) :
        for c in reversed(range(self.grille_3_stack_3.columnCount())) 
            layout = self.grille_3_stack_3.itemAtPosition(r, c)
            if layout is not None :
                layout.widget().deleteLater()
                #layout_1.widget().hide()
                self.grille_3_stack_3.removeItem(layout)

    self.liste_mots_vocabulaire.pop() 
    del self.dico_vocab_mot[index] 
    del self.dico_vocab_def[index] 

    print
    print "rowCount apres suppr", self.grille_3_stack_3.rowCount()

    print
    print self.dico_vocab_mot
    print self.dico_vocab_def
    print self.liste_mots_vocabulaire
    print
stack_3.addWidget(self.dico_vocab_mot[r], r+1, 0) self.grille
def supprimer_un_mot_vocab(self) :
    '''
    '''
    index = len(self.liste_mots_vocabulaire)-1
    for r in reversed(range(self.grille_3_stack_3.rowCount())) :
        for c in reversed(range(self.grille_3_stack_3.columnCount())) 
            layout = self.grille_3_stack_3.itemAtPosition(r, c)
            if layout is not None :
                layout.widget().deleteLater()
                #layout_1.widget().hide()
                self.grille_3_stack_3.removeItem(layout)

    self.liste_mots_vocabulaire.pop() 
    del self.dico_vocab_mot[index] 
    del self.dico_vocab_def[index] 

    print
    print "rowCount apres suppr", self.grille_3_stack_3.rowCount()

    print
    print self.dico_vocab_mot
    print self.dico_vocab_def
    print self.liste_mots_vocabulaire
    print
stack_3.addWidget(self.dico_vocab_def[r], r+1, 1) # Ecriture des n°s de lignes dans la partie mots de vocabulaire self.grille
def supprimer_un_mot_vocab(self) :
    '''
    '''
    index = len(self.liste_mots_vocabulaire)-1
    for r in reversed(range(self.grille_3_stack_3.rowCount())) :
        for c in reversed(range(self.grille_3_stack_3.columnCount())) 
            layout = self.grille_3_stack_3.itemAtPosition(r, c)
            if layout is not None :
                layout.widget().deleteLater()
                #layout_1.widget().hide()
                self.grille_3_stack_3.removeItem(layout)

    self.liste_mots_vocabulaire.pop() 
    del self.dico_vocab_mot[index] 
    del self.dico_vocab_def[index] 

    print
    print "rowCount apres suppr", self.grille_3_stack_3.rowCount()

    print
    print self.dico_vocab_mot
    print self.dico_vocab_def
    print self.liste_mots_vocabulaire
    print
stack_3.addWidget(self.dico_vocab_mot[r].setText(str(r+1)+'. '), r+1, 0) # Les données sont introduites dans une liste self.liste_mots_vocabulaire.append([self.dico_vocab_mot[r], self.dico_vocab_def[r]]) # ===================================================== # Signaux self.dico_vocab_mot[r].textChanged.connect(self.changements_phase_3) self.dico_vocab_def[r].textChanged.connect(self.changements_phase_3) # ===================================================== print 'self.dico_vocab_mot', self.dico_vocab_mot print 'self.dico_vocab_def', self.dico_vocab_def print self.liste_mots_vocabulaire

И удаление рядов виджетов вот так:

def supprimer_un_mot_vocab(self) :
    '''
    '''
    index = len(self.liste_mots_vocabulaire)-1
    for r in reversed(range(self.grille_3_stack_3.rowCount())) :
        for c in reversed(range(self.grille_3_stack_3.columnCount())) 
            layout = self.grille_3_stack_3.itemAtPosition(r, c)
            if layout is not None :
                layout.widget().deleteLater()
                #layout_1.widget().hide()
                self.grille_3_stack_3.removeItem(layout)

    self.liste_mots_vocabulaire.pop() 
    del self.dico_vocab_mot[index] 
    del self.dico_vocab_def[index] 

    print
    print "rowCount apres suppr", self.grille_3_stack_3.rowCount()

    print
    print self.dico_vocab_mot
    print self.dico_vocab_def
    print self.liste_mots_vocabulaire
    print

Все работает хорошо с первого раза, когда я добавляю ряды виджетов (например, пять рядов виджетов). Все тоже хорошо работает, если я удаляю строки (например, две строки виджетов). Но как только я решаю снова добавить строку (после удаления), она не работает должным образом: у меня получается шесть строк, а должно быть три.

Должно быть, это мой код для удаления строк, который не работает должным образом (хотя строки удаляются визуально). Что я делаю не так?


person ekdmekdm    schedule 19.11.2017    source источник
comment
Если вы хотите, чтобы мы вам помогли, вы должны предоставить минимальный, полный и проверяемый пример, то есть его можно воспроизведено, но для его выполнения требуется больше кода, лично мне лень завершать ваш код   -  person eyllanesc    schedule 19.11.2017
comment
Здравствуйте, eyllanesc, извините, я очень скоро постараюсь отправить более полный ответ. Это мое самое первое сообщение здесь (я хотел бы опубликовать полный код, который составляет 689 строк, но в тегах кода, ... не так хорошо ...).   -  person ekdmekdm    schedule 19.11.2017
comment
Вы должны предоставить минимальный, полный и поддающийся проверке пример. Если ваш код очень длинный, создайте другой проект только с той функциональностью, которая вызывает ошибку.   -  person eyllanesc    schedule 19.11.2017


Ответы (1)


QGridLayout не удаляет строки при удалении его виджетов, но пустые строки не занимают места, поэтому обычно вы их не замечаете. Если вы добавите виджеты сверх текущего количества строк, макет просто увеличится до необходимого размера. Таким образом, если текущее количество строк равно 5, и вы добавляете виджет в строку 10, количество строк немедленно изменится на 10, и будет создано пять пустых промежуточных строк.

Макет сетки всегда начинается с единицы строки. Но в вашем коде вы используете r + 1 при добавлении виджетов:

for r in range(self.grille_3_stack_3.rowCount()):
    ...
    self.grille_3_stack_3.addWidget(self.dico_vocab_mot[r], r+1, 0)
    self.grille_3_stack_3.addWidget(self.dico_vocab_def[r], r+1, 1)
    # Ecriture des n°s de lignes dans la partie mots de vocabulaire
    self.grille_3_stack_3.addWidget(self.dico_vocab_mot[r].setText(str(r+1)+'. '), r+1, 0)

Это пропустит первую строку и начнет добавлять виджеты с индексом строки 1. Таким образом, после добавления пяти рядов виджетов количество строк будет шесть, а не пять. И каждый раз, когда вы удаляете и снова добавляете виджеты, количество строк увеличивается на единицу.

Вместо этого ваш код должен выглядеть так:

for r in range(self.grille_3_stack_3.rowCount()):
    ...
    self.grille_3_stack_3.addWidget(self.dico_vocab_mot[r], r, 0)
    self.grille_3_stack_3.addWidget(self.dico_vocab_def[r], r, 1)
    self.dico_vocab_mot[r].setText(str(r+1)+'. ')

(Обратите внимание, что я также исправил здесь последнюю строку, которая раньше не имела смысла).

ИЗМЕНИТЬ:

Согласно комментариям, вот необходимые изменения, чтобы при каждом нажатии первой кнопки добавлялась одна строка, а при нажатии второй кнопки все строки очищались.

class EssaiQStackedWidget_Seq_Prof(QWidget) :
    def __init__(self, parent=None):
        ...
        self.dico_vocab_mot = {}
        self.dico_vocab_def = {}    
        self.liste_mots_vocabulaire = []

        self.liste_menu.currentIndexChanged.connect(self.affiche_phases)

    def ajouter_un_mot_vocab(self) :
        r = len(self.liste_mots_vocabulaire)
        self.dico_vocab_mot[r] = QTextEdit()
        self.dico_vocab_def[r] = QTextEdit()
        self.dico_vocab_mot[r].setMaximumWidth(180)
        self.dico_vocab_mot[r].setMinimumWidth(180)
        self.dico_vocab_mot[r].setMaximumHeight(54)
        self.dico_vocab_mot[r].setMinimumHeight(54)
        self.dico_vocab_def[r].setMaximumHeight(54)
        self.dico_vocab_def[r].setMinimumHeight(54)
        if r > 5 :
            self.dico_vocab_mot[r].setMaximumHeight(34)
            self.dico_vocab_mot[r].setMinimumHeight(34)
            self.dico_vocab_def[r].setMaximumHeight(34)
            self.dico_vocab_def[r].setMinimumHeight(34)
        self.grille_3_stack_3.addWidget(self.dico_vocab_mot[r], r, 0)
        self.grille_3_stack_3.addWidget(self.dico_vocab_def[r], r, 1)
        self.dico_vocab_mot[r].setText(str(r+1)+'. ')
        self.liste_mots_vocabulaire.append([self.dico_vocab_mot[r], self.dico_vocab_def[r]])
        self.dico_vocab_mot[r].textChanged.connect(self.changements_phase_3)
        self.dico_vocab_def[r].textChanged.connect(self.changements_phase_3)

    def supprimer_un_mot_vocab(self) :
        row = len(self.liste_mots_vocabulaire) - 1
        if row >= 0:
            for column in range(self.grille_3_stack_3.columnCount()):
                item = self.grille_3_stack_3.itemAtPosition(row, column)
                if item is not None:
                    item.widget().deleteLater()
            del self.liste_mots_vocabulaire[row]
            del self.dico_vocab_mot[row]
            del self.dico_vocab_def[row]
person ekhumoro    schedule 19.11.2017
comment
Спасибо за ответ эхуморо но если я заменю на этот код то создается только одна строка... при каждом нажатии кнопки создается только 1 строка. - person ekdmekdm; 20.11.2017
comment
ekhumoro, вы можете просмотреть весь код здесь: pastebin.com/EqsTVgrs - person ekdmekdm; 20.11.2017
comment
@ekdmekdm. Почему вы ожидаете, что этот код создаст более одной строки? Откуда берутся остальные строки? - person ekhumoro; 20.11.2017
comment
Прошу прощения, я конечно очень плохо делаю (а может и путаюсь в объяснениях)... вообще-то я хочу каждый раз при нажатии на кнопку... добавляется лишняя строчка. - person ekdmekdm; 20.11.2017
comment
@ekdmekdm. Таким образом, на самом деле вам не нужен цикл в ajouter_un_mot_vocab, и вы не хотите каждый раз сбрасывать dico_vocab_mot и т. д. до пустого dict. - person ekhumoro; 20.11.2017
comment
Да. Когда пользователь нажимает кнопку (Добавить словарную строку) в первый раз, QTextEdit будет добавлен в 0, 0, другой в 0, 1,... когда пользователь нажимает кнопку второй раз, QTextEdit будет добавлен в 1, 0, еще один в 1, 1,... так что каждый раз, когда пользователь нажимает кнопку, будет добавляться новая строка QTextEdit... Да, я не хочу продолжать сбрасывать dico_vocab_mot (а также dico_vocab_def). На самом деле строка словаря включает в себя два QTextEdit (один для самого словарного слова, а другой для определения словарного слова). - person ekdmekdm; 20.11.2017
comment
эхуморо, я ложусь спать, здесь во Франции уже поздно, и я завтра рано встаю (откуда ты?). Я проверю ваш код завтра. (-› где галочка?). Если вы согласны, я дам вам знать, если это работает для меня. - person ekdmekdm; 20.11.2017
comment
Привет эхуморо, я только что попробовал твой код, создание строк работает нормально но в момент удаления каждой строки (одной за другой а не все одновременно) ну и кнопка Удалить строку лексики удаляет все строки выстрела. Я хотел бы, чтобы каждый раз, когда вы нажимаете эту кнопку, удалялась последняя строка виджетов. - person ekdmekdm; 20.11.2017
comment
Вау! Ваш более поздний код работает отлично!!! Большое спасибо эхуморо! Я иногда консультировался со stackoverflow, но я признаю, что это действительно здорово. Если я смогу помочь на днях... - person ekdmekdm; 20.11.2017