如何创建一组UI元素,您可以迭代

How to create a group of UI elements that you are able to iterate through

本文关键字:元素 迭代 UI 何创建 创建 一组      更新时间:2023-10-16

我有一个应用程序作为班级的项目,其中包含游戏吊床和其他人。
我有一个行编辑输入字段供用户猜测字母。此输入仅限于1个字母。
我想有一个for循环,该循环检查用户输入是否与游戏中的任何字母匹配目标单词,并且是否将其放在屏幕上。
我有一堆标签,我打算将单个字母放入其中,每个字母都与正确的单词字符串中的字母放置相对应。
如何将QT UI元素放入数据结构中,以便我可以以循环访问它们?
这是我在网上查找后尝试的一些代码,以使您了解我要做什么。

int Hangman::check_input(QString input){
    QList<QObject *> visible_word = {ui->label_0, ui->label_1,ui->label_2, ui->label_3,ui->label_4};
    int i;
    for (i = 0; i < current_word.length(); i++){
        if (input == current_word[i]){
            ui->visible_word[i]->text() == current_word[i];
        }
    }
}

您所做的工作有效,并且假设英语,因为可能的字母数可能固定为26(除非您出于某种原因允许非字母字符)错误。如果标签的数量是可变的或巨大的,这只是有问题的,而且这里似乎没有这种情况。

您还可以做的就是使用findChildren方法,并且有几种变体。最简单的是,如果您的所有标签都属于同一小部件,并且在同一父母下没有其他QLabel实例:

QList <QLabel *> parent->findChildren <QLabel *> ();

否则,您可能需要使用接受正则表达式以匹配子名称的变体:

QList <QLabel *> parent->findChildren <QLabel *> (QRegExp ("^label_"));

请注意,在两种情况下的顺序可能不是您想要使用所选字母填充标签的内容。文档没有说,但是我相信返回的顺序反映了孩子的创建顺序。由于您在QT设计师中创建了这些命令,因此该顺序可能不可靠;例如,如果您错过了中间的12号并将其添加在其他人之后,则Label_12将在列表中进行最后。根据您的其余方法,这可能无关紧要。如果您需要您的列表按标签0,标签1等顺序,那么您当前的机制可能是您想要的。

看起来很蛮力,但有时是完全可以接受的。

从您拥有的代码开始,让我们对其进行修复,以便它具有正确的方法签名,以使其编译:

/// Returns the number of newly matched letters.
int Hangman0::check_input(QChar input) {
   int matched{};
   std::array<QLabel*, 5> visible_word = {ui->label_0, ui->label_1,ui->label_2, ui->label_3,ui->label_4};
   for (int i{}; i < current_word.length(); i++) {
      auto const ch = current_word.at(i);
      if (input == ch && visible_word[i]->text() != ch) {
         visible_word[i]->setText(ch);
         ++ matched;
      }
   }
   return matched;
}

但是,手动列举这些UI元素的意义很小,也可以手动将它们插入UI文件中的布局中。取而代之的是,将UI文件带有空布局,然后根据需要以编程方式插入元素。首先,让我们从最小.ui文件中近似UIC输出:

// https://github.com/KubaO/stackoverflown/tree/master/questions/hangman-42261596
#include <QtWidgets>
#include <forward_list>
namespace Ui { // Approximate uic output
struct Hangman {
   QFormLayout * topLayout;
   QHBoxLayout * lettersLayout;
   QLineEdit * letterEntry;
   QPushButton * setup;
   void setupUi(QWidget * widget) {
      topLayout = new QFormLayout{widget};
      topLayout->addRow(lettersLayout = new QHBoxLayout);
      topLayout->addRow("Guess", letterEntry = new QLineEdit);
      letterEntry->setMaxLength(1);
      topLayout->addRow(setup = new QPushButton{"Setup"});
   }
};
}

然后,让我们设计一个基本的Hangman游戏小部件。我们可以在std::forward_list中按值保持字母标签 - 这使生活相对容易,我们不必处理任何形式的明确内存管理。

class Hangman : public QWidget {
   Q_OBJECT
   Ui::Hangman ui;
   QString m_currentWord;
   std::forward_list<QLabel> m_letters;
public:
   explicit Hangman(QWidget * parent = nullptr) :
      QWidget{parent}
   {
      ui.setupUi(this);
      connect(ui.letterEntry, &QLineEdit::returnPressed, [this]{
         auto const text = ui.letterEntry->text();
         if (!text.isEmpty())
            checkInput(text[0]);
      });
      connect(ui.setup, &QPushButton::clicked, [this]{
         setWord(QInputDialog::getText(this, "Setup", "Secret word:",
                                       QLineEdit::Normal, m_currentWord)); // a hack
      });
      setWord("Hello");
   }
   void setWord(const QString & word) {
      m_currentWord = word.toUpper();
      m_letters.clear();
      auto letter = m_letters.before_begin();
      for (int i{}; i < word.size(); ++i) {
         letter = m_letters.emplace_after(letter);
         letter->setFrameShape(QFrame::Box);
         ui.lettersLayout->addWidget(&*letter);
      }
   }
   int checkInput(QChar input) {
      int matched{};
      input = input.toUpper();
      auto letter = m_letters.begin();
      for (int i{}; i < m_currentWord.size(); ++i) {
         if (m_currentWord.at(i) == input) {
            letter->setText(input);
            matched ++;
         }
         letter ++;
      }
      return matched;
   }
};
int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   Hangman hangman;
   hangman.show();
   return app.exec();
}
#include "main.moc"