質問

I am new to Qt and I am doing some practice with simple examples.

I just wanted to test my knowledge with a simple application, by coding, in which user types a text in QLineEdit widget and the text will be shown in QLabel. There is no need for it to be useful. I just want to try.

While compiling the application, I get no errors. However, QLabel and QLineEdit widgets are not visible when the window is opened.

My codes are here:

Window.h

#ifndef WINDOW_H
#define WINDOW_H

#include <QMainWindow>

class QGridLayout;
class QLabel;
class QLineEdit;

class Window : public QMainWindow
{
    Q_OBJECT

public:
    explicit Window(QWidget *parent = 0);

private:
    QGridLayout *mainLayout;
    QLabel *label;
    QLineEdit *lineEdit;
};

#endif // WINDOW_H

Window.cpp

#include "Window.h"
#include <QGridLayout>
#include <QLineEdit>
#include <QLabel>

Window::Window(QWidget *parent)
    : QMainWindow(parent)
{
    mainLayout = new QGridLayout;
    label = new QLabel(tr("Text"));
    lineEdit = new QLineEdit;

    mainLayout->addWidget(label, 0, 0);
    mainLayout->addWidget(lineEdit, 1, 0);
    setLayout(mainLayout);

    connect(lineEdit, SIGNAL(textChanged(QString)),
            label, SLOT(setText(QString)));
}

main.cpp

#include <QApplication>
#include "Window.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    Window window;
    window.show();

    return app.exec();
}

I couldn't find any mistake in the code.

Thanks, in advance.

役に立ちましたか?

解決

A QMainWindow must have a central widget, even if it's just a placeholder. Also note that it has its own layout for adding toolbars, menubars, etc. - so you probably want to set the layout (mainLayout in your code) for the central widget instead.

Check the QMainWindow class reference for details.

To make your widgets visible in the main window, you could modify your constructor like this:

Window.cpp

#include "Window.h"
#include <QGridLayout>
#include <QLineEdit>
#include <QLabel>

Window::Window(QWidget *parent)
    : QMainWindow(parent)
{
    QWidget* someWidget = new QWidget(this);
    mainLayout = new QGridLayout;
    label = new QLabel(tr("Text"));
    lineEdit = new QLineEdit;

    mainLayout->addWidget(label, 0, 0);
    mainLayout->addWidget(lineEdit, 1, 0);
    someWidget->setLayout(mainLayout);

    connect(lineEdit, SIGNAL(textChanged(QString)),
             label, SLOT(setText(QString)));

    setCentralWidget(someWidget);
}

他のヒント

Use the QWidget instead of QMainWindow. The latter is not meant to be used directly with a layout like you're doing. Don't use QMainWindow unless you explicitly need the features it offers (toolbars, dock areas, etc.). If you really want to use QMainWindow, then Akos's excellent answer shows how to do it.

Any widget, even a simple QLabel can be your "main" widget.

You also don't need all the complication of dynamically allocating the widgets.

Simply do:

class Window : public QWidget
{
   Q_OBJECT
   QGridLayout m_layout;
   QLabel m_label;
   QLineEdit m_lineEdit;
public:
   explicit Window(QWidget *parent = 0);
};

Then the constructor reduces to:

Window::Window(QWidget *parent)
   : QWidget(parent), m_layout(this), m_label(tr("Text"))
{
   m_layout.addWidget(&m_label, 0, 0);
   m_layout.addWidget(&m_lineEdit, 1, 0);
   connect(&m_lineEdit, SIGNAL(textChanged(QString)),
           &m_label, SLOT(setText(QString)));
}

To try things out, you may wish to put it all in a single main.cpp file:

#include <QApplication>
#include <QLabel>
#include <QTextEdit>

class Window : public QWidget
{
   Q_OBJECT
   QGridLayout m_layout;
   QLabel m_label;
   QLineEdit m_lineEdit;
public:
   explicit Window(QWidget *parent = 0) : QWidget(parent), 
     m_layout(this), m_label(tr("Text"))
   {
     m_layout.addWidget(&m_label, 0, 0);
     m_layout.addWidget(&m_lineEdit, 1, 0);
     connect(&m_lineEdit, SIGNAL(textChanged(QString)),
             &m_label, SLOT(setText(QString)));
   }
};

int main(int argc, char *argv[])
{
   QApplication app(argc, argv);    
   Window window;
   window.show();
   return app.exec();
}

#include "main.moc"

Make sure that you re-run qmake on the project before you attempt to compile it.

For a given foo.cpp file, you need to #include "foo.moc" at the end when you want to run the .cpp file through moc. You might want, for example, a private QObject-derived class that lives in a .cpp file and is used in that file. You don't have to separate the interface of this class into a separate header file, then. This was much more important in Qt 4 and pre-C++11, when you had no lambdas and had to put slots into dedicated classes. In Qt 5 you can connect a signal to a functor written in-place, so there's much less need for local helper object classes just to write a slot or two.

This approach is very useful when you're experimenting. Having the <1000 lines of code spread about three or more files is rather counterproductive in such cases. Short experiments are all about conciseness. Implementations go into class declarations a-la Java, you run the single main.cpp file through moc and append the moc output at the end (via #include "main.moc"). Default Qt Creator-generated templates are for "big" applications, not for experiments.

For inspiration, there's about 200 such mostly single-file examples on my stackoverflown answer repository :) Each example's folder has the SO question number appended at the end, to make it easy to look up the SO question for context.

If you're concerned about the interface headers being polluted with implementation details, the pimpl idiom comes to the rescue:

// window.h
#ifndef MY_WINDOW_H
#define MY_WINDOW_H

#include <QWidget>
#include <QScopedPointer>

// This only provides a public interface.
class WindowPrivate;
class Window : public QWidget {
  Q_OBJECT
  Q_DECLARE_PRIVATE(Window)
  QScopedPointer<WindowPrivate> const d_ptr;
public:
  explicit Window(QWidget *parent = 0);
  ~Window();
  QString text() const;
};

#endif

// window.cpp

#include "window.h"
#include <QLabel>
#include <QLineEdit>
#include <QGridLayout>

class WindowPrivate {
  Q_DISABLE_COPY
public:
  explicit WindowPrivate(Window *);
  QGridLayout layout;
  QLabel label;
  QLineEdit lineEdit;
};

Window::Window(QWidget * parent) : QWidget(parent), d_ptr(new WindowPrivate(this))
{
  Q_D(Window);
  // This code really belongs in WindowPrivate constructor.
  // It is shown here to illustrate how the non-const pimpl is accessed.
  connect(&d->lineEdit, SIGNAL(textChanged(QString)),
          &d->label, SLOT(setText(QString)));
}

// Needed here since the ~WindowPrivate is not visible outside of this file.
Window::~Window() {}

QString Window::text() const {
  Q_D(const Window);
  // This is how you access const pimpl
  return d->label.text();
}    

WindowPrivate::WindowPrivate(Window * window) :
  layout(window), label(tr("Text"))
{
  layout.addWidget(label, 0, 0);
  layout.addWidget(lineEdit, 1, 0);
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top