2017-02-15 36 views
1

我有一个应用程序,我正在为一个包含游戏hang子手和其他类的项目制作一个应用程序。
我有一个线路编辑输入字段供用户猜测一个字母。此输入限制为1个字母。
我想要一个for循环来检查用户输入是否匹配来自游戏目标单词的任何字母,如果是,则会将该字母放在屏幕上。
我有一堆标签,我打算放入一个单一的字母,每个安排与正确的字符串中的字母放置相对应。
如何将qt ui元素放入数据结构以便我可以在for循环中访问它们?
以下是我在网上查看后尝试的一些代码,以便让您了解我正在尝试执行的操作。如何创建一组您可以遍历的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]; 
     } 
    } 
} 

回答

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" 
+0

谢谢!这似乎是处理它的好方法 –

2

你做了什么工作,并假设英语,因为可能的字母的数量很可能定为26(除非你允许出于某种原因非字母字符),没什么不妥的地方。如果标签的数量是可变的或巨大的,这只是一个问题,在这里情况似乎都不是这样。

你也可以做的是使用findChildren方法,并且有几种变化。最简单的一个是,如果您的所有标签都是父相同的部件,并有同样的父母在任何其他QLabel实例:

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

否则,你可能会需要使用接受一个正则表达式的变化匹配孩子的名字:

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

注意,在这两种情况下的顺序可能不是你想要的东西与所选择的字母填入您的标签。文档没有说明,但我相信返回的订单反映了创建子项的顺序。由于您是在Qt Designer中创建它们的,因此该订单可能不可靠;例如,如果您错过了中间的第12个数字并将其添加到其他数字之后,那么label_12将在列表中最后一个。这取决于你的其他方法,这可能也可能不重要。如果你需要你的列表按照标签0,标签1等的顺序,那么你当前的机制可能就是你想要的。

它似乎是蛮力,它是,但有时这是完全可以接受的。