Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt GUI _ Главное меню

Автор: Don 10.5.2008, 15:34

Как добавить главное меню на форму, чтоб оно там нормально выглядело? У меня на форме уже рисуется рисунок и имеется кнопка. Теперь хочу добавить главное меню. Пытался добавлять путём собирания всех виджетов в один Layout, получается билеберда.

Автор: Litkevich Yuriy 10.5.2008, 15:37

у QMainWindow есть необходимый функционал

Автор: Don 10.5.2008, 15:49

Цитата(Litkevich Yuriy @ 10.5.2008, 15:37) *
у QMainWindow есть необходимый функционал

А по подробней можно? Мне нужно именно добавить на форму.

Автор: Litkevich Yuriy 10.5.2008, 15:53

лучше, если б твое окно(форма) было бы наследником http://crossplatform.ru/documentation/qtdoc4.3/qmainwindow.phphttp://crossplatform.ru/documentation/qtdoc4.3/qmainwindow.php, там есть метод setMenuBar(), он устанавливает обект типа http://crossplatform.ru/documentation/qtdoc4.3/qmenubar.php

Автор: Don 10.5.2008, 16:15

Цитата(Litkevich Yuriy @ 10.5.2008, 15:53) *
лучше, если б твое окно(форма) было бы наследником http://crossplatform.ru/documentation/qtdoc4.3/qmainwindow.phphttp://crossplatform.ru/documentation/qtdoc4.3/qmainwindow.php, там есть метод setMenuBar(), он устанавливает обект типа http://crossplatform.ru/documentation/qtdoc4.3/qmenubar.php

У меня окно наследует от QWidget

Автор: Litkevich Yuriy 10.5.2008, 16:21

измени, я думаю ты ничего не потеряшь

Автор: Don 10.5.2008, 16:26

Цитата(Litkevich Yuriy @ 10.5.2008, 16:21) *
измени, я думаю ты ничего не потеряшь

Теряется
А что добавить в форму главное меню, если форма наследник QWidget, нельзя?

Автор: Litkevich Yuriy 10.5.2008, 16:27

например, что? Ведь QMainWindow тоже наследник QWidget.

Автор: Don 10.5.2008, 16:30

Цитата(Litkevich Yuriy @ 10.5.2008, 16:27) *
например, что? Ведь QMainWindow тоже наследник QWidget.

Как я поменял QWidget на QMainWindow, так у меня всё пропало.

Автор: Litkevich Yuriy 10.5.2008, 16:37

ага, у тебя все на одном виджете было, тогда так:
делаешь подкласс от QMainWindow, и методом setCentralWidget() устанавливаешь свой класс, текущий, а потом методом setMenuBar() устанавливаешь панель меню, так наверное проще будет, т.к. окошко ты уже создал.

покажи свой main()

Автор: Don 10.5.2008, 16:58

Цитата(Litkevich Yuriy @ 10.5.2008, 16:37) *
ага, у тебя все на одном виджете было, тогда так:
делаешь подкласс от QMainWindow, и методом setCentralWidget() устанавливаешь свой класс, текущий, а потом методом setMenuBar() устанавливаешь панель меню, так наверное проще будет, т.к. окошко ты уже создал.

покажи свой main()


Если установить свой класс через setCentralWidget(), то к окну добавится тока рисунок, а кнопка пропадает.

CODE

QApplication app(argc,argv);
// Установим кодировку для функции перевода tr()
QTextCodec::setCodecForTr(QTextCodec::codecForName("Windows-1251"));

// Сделаем симпотичный вид
QStyle *pStyle = QStyleFactory::create("Plastique");//Cleanlooks Plastique windows
QApplication::setStyle(pStyle); //
app.setPalette(pStyle->standardPalette());

Main *menu = new Main;
Life *board = new Life;

QWidget *window = new QWidget;
window->setWindowTitle(QObject::tr("Жизнь - Игра"));
window->setGeometry(100,100,700,550); //рамки окна
//window.setFixedSize(700,550); //фиксируем границы

QPushButton *btngo = new QPushButton(QObject::tr("Вперед"));
btngo->setFixedSize(70,28);
QObject::connect(btngo, SIGNAL(clicked()), board, SLOT(ris()));



QVBoxLayout *lay = new QVBoxLayout;
//собираем все виджеты вместе
lay->addWidget(menu);
lay->addWidget(board);
lay->addWidget(btngo);

window->setLayout(lay);
//menu->show();
window->show();
return app.exec();

Автор: Litkevich Yuriy 10.5.2008, 17:12

Цитата(Don @ 10.5.2008, 20:58) *
то к окну добавится тока рисунок, а кнопка пропадает.


это потому, что ты кнопку в main'е делаешь, надо сделать виджет который будет реализовыватьосновную функциональность окна, как отдельный класс , посути это твой
...
QWidget *window = new QWidget;
...




Вот пример с главным окном и меню:  1.ZIP ( 2.8 килобайт ) : 183

тебе надо изменить конструктор класса MyWidget (class2.cpp) удалить от туда мое, и переместить из main'а кнопку, компоновщик, ну и игровое поле, а виджет window, уже не нужен, т.к. MyWidget и выполняет его роль.
Life    *board = new Life;
QPushButton    *btngo = new QPushButton(QObject::tr("Вперед"));
QVBoxLayout   *lay = new QVBoxLayout;

ну и не забудь приинклюдить, заколовочник своего игрового поля

---
P.S. Там косячек с кодировкой, проверь и исправь, одни файлы в виндовозной, другие в UTF-8.

Автор: Don 10.5.2008, 17:58

Заработало, спасибо!
Вот только почему в этом случае для окна не работают такие фукции как:
setWindowTitle();
setGeomtry();
setFixedSize(); //работает как задание минимального размера окна
и т.д. ?

Автор: Litkevich Yuriy 10.5.2008, 18:09

приведи пример, где не работает.
заголовок окна - заголовок MyMainWindow , в его конструкторе.
фиксированую геометрию виджета можно задать так,

setMaximumSize(...);
setMinimumSize(...);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

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

Автор: Don 10.5.2008, 18:15

Цитата(Litkevich Yuriy @ 10.5.2008, 18:09) *
приведи пример, где не работает.
заголовок окна - заголовок MyMainWindow , в его конструкторе.
фиксированую геометрию виджета можно задать так,
setMaximumSize(...);
setMinimumSize(...);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

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


Я размеры устанавливал в конструкторе MyMainWindow : QMainWindow, где и делал это окно центральным виджетом. Вот там и не работает.

А как добавить пружинку программно? Я её как-то добавлял в дизайнере, а так не.

Автор: Litkevich Yuriy 10.5.2008, 18:37

Цитата(Don @ 10.5.2008, 22:15) *
Я её как-то добавлял в дизайнере, а так не.

http://crossplatform.ru/documentation/qtdoc4.3/qboxlayout.php#addStretch
Цитата(Don @ 10.5.2008, 22:15) *
Я размеры устанавливал в конструкторе MyMainWindow : QMainWindow, где и делал это окно центральным виджетом. Вот там и не работает.

Главное окно плохо делать фиксированым, это неудобно для пользователя. если тебе надо фиксировать размер виджета, то его и фиксируй.
// Рекомендация размера, для Layout'ов
QSize MyFixWidget::sizeHint() const
{
    return QSize(столько,на_столько);
}


в заголовочнике так:
...
virtual QSize sizeHint() const;
...

Автор: Don 10.5.2008, 18:46

А как насчёт setWindowTitle() ?

Автор: Litkevich Yuriy 10.5.2008, 18:53

у тебя сейчас такая структура получается:
MyMainWindow -> MyWidget -> Life, btngo
если тебе надо фиксированый размер Life, то
либо в нем реализуешь sizeHint(),
либо в MyWidget задаешь фиксированый размер Life'а

---
у меня в конструкторе класса MyMainWindow
setWindowTitle(tr("Привет"));
делает свою работу

---
подправил 14 пост, забыл про косячек с отображением.

Автор: Don 10.5.2008, 23:27

У меня такая штука. В моей проге при нажатии на Файл->Новая Игра, должно задаться imatrix рандомные значения, но этого не происходит. Помогите плиз выйти из ситуации.

И подскжите плиз как обращаться к данным созданного класса при работе с Главным меню.

Life.h

CODE

#ifndef LIFE_H
#define LIFE_H

#include <QtGui>
#include <QWidget>
#include <QPainter>
#include <QMainWindow>

class Life : public QWidget
{
Q_OBJECT
public:
Life(QWidget *parent = 0);
int imatrix[17][17];
void smile(int x, int y );

protected:
virtual void paintEvent(QPaintEvent*);

public slots:
void ris();

private:
void over();
int newmatrix[17][17];
};
#endif


Life.cpp
CODE

#include <QApplication>
#include <QPainter>
#include <QTextCodec>
#include <QFont>
#include <QPushButton>
#include <QtGui>
#include <math.h>
#include <time.h>
#include <QPushButton>
#include <QMainWindow>
#include "Life.h"

Life::Life(QWidget *parent) : QWidget(parent)
{
srand(time(0));
for (int i = 0; i < 10; i++)
for(int j = 0; j < 10; j++) imatrix[i][j] = rand()%3;
}
void Life::ris()
{
int count = 0;
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (imatrix[i+1][j] == 1) count++;
if (imatrix[i+1][j+1] == 1) count++;
if (imatrix[i+1][j-1] == 1) count++;
if (imatrix[i][j+1] == 1) count++;
if (imatrix[i][j-1] == 1) count++;
if (imatrix[i-1][j-1] == 1) count++;
if (imatrix[i-1][j] == 1) count++;
if (imatrix[i-1][j+1] == 1) count++;
if (count > 1 && count < 4 && imatrix[i][j] == 1) newmatrix[i][j] =1;
if (count == 3 && imatrix[i][j] == 0) newmatrix[i][j] =1;
if (count > 3) newmatrix[i][j] = 0;
if (count < 2) newmatrix[i][j] = 0;
count = 0;

}
}

for (i = 0; i < 10; i++)
for (int j = 0; j < 10; j++) imatrix[i][j] = newmatrix[i][j];
repaint();

}
void Life::paintEvent(QPaintEvent*)
{
qDebug() << "paintEvent";
QPainter paint(this);
int x = 15;
int y;
paint.setRenderHint(QPainter::Antialiasing,true);
paint.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap));
paint.setBrush(QBrush(Qt::white, Qt::SolidPattern));
for (int i=1; i<=11; i++) //рисуем клетку
{
paint.drawLine(x,15,x,515);

x = x + 50;
}
x = 15;
y = 19;
for (i=1; i<=11; i++)
{
paint.drawLine(15,x,515,x);
x = x+50;
}
x = 19;
paint.setPen(QPen(Qt::white)); //рисуем прямоугольники в клетках
paint.drawRoundRect(19,19,42,42);
for (i=1; i<=10; i++)
{
for (int j=1; j<=10; j++)
{
paint.drawRoundRect(x,y,42,42);
x = x+50;
}
x = 19;
y = y +50;
}

x = 20;
y = 40;
for (int i = 0; i < 10; i++) //рисуем смайлики
{
for(int j = 0; j < 10; j++)
{
if (imatrix[i][j] == 1) smile(x,y);
x = x + 50;
}
y = y + 50;
x = 20;
}

int k = 0;
for (int i = 0; i < 10; i++)
{
for(int j = 0; j < 10; j++)
{
if (imatrix[i][j] == 1) k++;
}
}
if (k == 0) over();
paint.end();
}

void Life::smile(int x, int y) //рисуем смайлик
{
QPainter paintsmile(this);
paintsmile.setRenderHint(QPainter::Antialiasing,true);
paintsmile.setPen(QPen(Qt::black));
paintsmile.setBrush(QBrush(Qt::yellow));
paintsmile.drawEllipse(x,y-20,40,40);
paintsmile.drawEllipse(x+11,y-5,3,3);
paintsmile.drawEllipse(x+26,y-5,3,3);
QRect rect(x+6,y-24,28,39);
int a = 30 * 112;
int b = 120 * 16;
paintsmile.drawArc(rect,a,B);
paintsmile.end();
}
void Life::over()
{
QPainter paint(this);
paint.setRenderHint(QPainter::Antialiasing,true);
paint.setPen(QPen(Qt::black));//, 1, Qt::SolidLine, Qt::RoundCap));
paint.setBrush(QBrush(Qt::black, Qt::SolidPattern));
paint.setFont(QFont("Times",65));
paint.drawText(50,250,"Game Over");
paint.end();

}


mainwindow.h
CODE

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "Life.h"

class QAction;
class QActionGroup;
class QLabel;
class QMenu;
class QPushButton;
class Life;

class mainwindow : public QMainWindow
{
Q_OBJECT

public:
mainwindow(QWidget *parent = 0);

public slots:
void restart();

private:
void createActions();
void createMenus();

Life *board;
QWidget *gwt;
QPushButton *btngo;
QMenu *fileMenu;
QAction *newGame;
QAction *exitAct;
};

#endif


mainwindow.cpp
CODE

#include <QtGui>
#include <time.h>
#include "Life.h"
#include "mainwindow.h"

mainwindow::mainwindow(QWidget *parent)
{
QWidget *wgt = new QWidget;
setWindowTitle(tr("Жизнь - Игра"));
setGeometry(100,100,700,570);
setFixedSize(700,570);
setCentralWidget(wgt);

Life *board = new Life;

QPushButton *btngo = new QPushButton(QObject::tr("Вперед"));
btngo->setFixedSize(70,28);
QObject::connect(btngo, SIGNAL(clicked()), board, SLOT(ris()));
QHBoxLayout *lay = new QHBoxLayout;
lay->addWidget(board);
lay->addWidget(btngo);
wgt->setLayout(lay);
createActions();
createMenus();
}

void mainwindow::createActions()
{
newGame = new QAction(tr("Новая Игра"),this);
connect(newGame, SIGNAL(triggered()), this, SLOT(restart()));

exitAct = new QAction(tr("Выход"),this);
connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));

}

void mainwindow::createMenus()
{
fileMenu = menuBar()->addMenu(tr("Файл"));
fileMenu->addAction(newGame);
fileMenu->addAction(exitAct);

}
void mainwindow::restart()
{
srand(time(0));
for (int i = 0; i < 10; i++)
for(int j = 0; j < 10; j++) board->imatrix[i][j] = rand()%3;

}

Автор: Litkevich Yuriy 10.5.2008, 23:48

проверь в слот mainwindow::restart() входит программа? Сообщение пошли для проверки. да и кстати про принудительный репаинт, я тебе в прошлой истории говорил.

Автор: Don 11.5.2008, 17:23

Цитата(Litkevich Yuriy @ 10.5.2008, 23:48) *
проверь в слот mainwindow::restart() входит программа? Сообщение пошли для проверки. да и кстати про принудительный репаинт, я тебе в прошлой истории говорил.


Сам слот restart() работает. Проверял с помощью QMessaggeBox. А вот када в нём обращаешся к даннам класса Life, работа проги прекращается и выпадает окошко с предупреждением:

Unhandled exception at 0x0040270e in life.exe: 0xC0000005: Access violation writing location 0xcdcdcde1.

и внизу три кнопки Continue, Break, Ignore (не дуступна).
Это связано по ходу с кривым обращением к данным класса Life. Помогите плиз решить проблему.

Автор: Don 11.5.2008, 21:15

Ладно, поскажите пожалуйста хотя бы как средствами С++ или Qt можно найти и запустить exe-файл?

Автор: Admin 11.5.2008, 21:30

Примерно так:

     QObject *parent;
     // ...
     QString program = "./path/to/Qt/examples/widgets/analogclock";
     QStringList arguments;
     arguments << "-style" << "motif";

     QProcess *myProcess = new QProcess(parent);
     myProcess->start(program, arguments);


Цитата(Don @ 11.5.2008, 17:23) *
Это связано по ходу с кривым обращением к данным класса Life. Помогите плиз решить проблему.
Угу именно так, я бы тебе посоветовл сделать так:
1. Из конструктора класса Life вынести код:
srand(time(0));
for (int i = 0; i < 10; i++)
    for(int j = 0; j < 10; j++) imatrix[i][j] = rand()%3;}
в отдельную функцию, и вызывать данную функцию в конструкторе и в слоте restart. Ну и правки нужно будет делать не в двую участках кода, а только в данной функции класса.

2. Посмотри в отладчике указатель board валиден или нет, если не валиден, то ищи где он у тебя портится...

Автор: Don 11.5.2008, 21:43

Заносил в отдельную фукцию, всё равно из mainwindow.cpp не работает. А что значит валиден?

Автор: Litkevich Yuriy 11.5.2008, 21:50

валиден - показывает в конкретное место, а не на звезды :)

Автор: ViGOur 11.5.2008, 21:51

Указывает на валидный участок памяти, а не на 0x000000, 0xffffff или 0xfefefe и т.д.

Наверняка исключение простреливается именно из-за этого.

Автор: Don 11.5.2008, 22:09

А смотреть в отладчике как? Это компилировать прогу построчно что-ли? Как им вобще пользоваться?

Автор: ViGOur 11.5.2008, 22:12

Вот можно почитать хорошии статьи по этому поводу:
http://www.rsdn.ru/article/vcpp/vcdebug_.xml


Автор: Don 11.5.2008, 22:17

Цитата(ViGOur @ 11.5.2008, 22:12) *
Вот можно почитать хорошую статью по этому поводу: http://www.rsdn.ru/article/vcpp/vcdebug-1.xml

Спасибо, конечно! Я прочту. Но можно в кратце, в двух словах. Как его запустить? И где мне там глянуть валиден ли мой board или нет? Просто нужно поскорей

Автор: ViGOur 11.5.2008, 22:25

Нужно поставить точку останова, на твоей проблемной строчке. Делается это так, поставь курсор на той строчке, что ты хочешь отладить и нажми кнопку F9, после чего с лева от нее должен появится красный кружечек, который называется брэкпоинт.
Затем нажимаешь кнопку F5, после чего запускается твое приложение, и делаешь в нем то, чтобы выполнился твой проблемный участок кода, когда это произойдет студия бросит тебя на установденный брэйкопоинт. Далее, чтобы пошагово ходить нужно работать клавишами F10 (шаг далее) или F11 (шаг в функцию)...

Далее объяснять не буду, так как назначение разного рода окошек описывается в статье...


p.s. я тебе выше добавил еще статей. :)

Автор: Don 11.5.2008, 23:20

Скажите, вот если я в заголовочном файле mainwndow.h объявил объект Life *board А потом в mainwindow.срр в конструкторе и других функциях вроде как заново объявляю его
Life *board = new Life;
то получается создаются совсем разные объекты?
И почему если объявить объект тока в заголовочном файле и не объявлять ещё в конструкторе и функциях, и обращатся с ним как с созданным объектом, то ничего не рабатает?

Автор: Litkevich Yuriy 12.5.2008, 7:48

Объявлять надо в одном месте, в хидере:

Life *board; // объявил
,
а в реализации, например в конструкторе:
board = new Life; // создал обект тапа Life и связал его с указателем

Автор: ViGOur 12.5.2008, 7:49

Немного терминологии:

Life *board1;                 // Объявление
board1 = new Life;         // Определение
Life *board2 = new Life; // Инициализация

Насчет разных указателей на объект:
Life *board=0;
board = new Life(); // для указателя board выделена память, и он указывает на определенный участок ее.
board = new Life(); // снова для указателя board выделена память, и он указывает на другой участок памяти, чем указывал строкой выше.

Автор: Tonal 12.5.2008, 7:54

Для локальных переменных объявление и определение совпадают. Кроме того, они часто совмещаются с инициализацией.

Не совпадают объявление и определение для внешних глобальных переменных, статических данных членов, неинлайновых функций и экспортных шаблонов (вроде ничего не забыл).

Автор: Don 12.5.2008, 18:00

Цитата(ViGOur @ 12.5.2008, 7:49) *
Немного терминологии:
Life *board1;                 // Объявление
board1 = new Life;         // Определение
Life *board2 = new Life; // Инициализация

Во, спасибо! Я нашёл ошибку. Нада было объект моего класса не инициализировать, а определять.

Автор: ViGOur 12.5.2008, 18:58

Цитата(Don @ 12.5.2008, 19:00) *
Во, спасибо! Я нашёл ошибку. Нада было объект моего класса не инициализировать, а определять.
Главное, чтобы ты запомнил, и больше не делал эту ошибку. ;)

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)