Форум программистов, компьютерный форум, киберфорум
C++ Qt
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.81/16: Рейтинг темы: голосов - 16, средняя оценка - 4.81
 Аватар для soon
2554 / 1319 / 178
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1

Проблема с QScrollArea

06.10.2011, 18:21. Показов 3123. Ответов 1
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток.

Пишу Game of life. Собственно, простенькая реализация логики на консоли есть, решил перенести её на GUI. До некоторых пор все было хорошо, пока не столкнулся со ScrollArea. Большую часть кода писал почти полностью с книги М. Саммерфилда. "Qt4", и вот, что получилось.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//gamemap.h
#ifndef GAMEMAP_H
#define GAMEMAP_H
 
#include <QWidget>
#include <QColor>
 
class GameMap : public QWidget
{
    Q_OBJECT
 
public:
    GameMap(QWidget *parent = 0);
    ~GameMap();
 
    //void setRows(const int r) { rows = r; }
    //void setColumn(const int c) { columns = c; }
    void clearMap();//k
    QSize sizeHint() const;
 
    //bool getPause() const { return pause; }
    //int getSize() const { return size; }
 
    void step();
 
protected:
    void paintEvent(QPaintEvent *event);//k
    void mousePressEvent(QMouseEvent *event);//k
    void mouseMoveEvent(QMouseEvent *event);//k
    void showEvent(QShowEvent *event);//k
    void timerEvent(QTimerEvent *event);//k
    void hideEvent(QHideEvent *event);//k
 
private:
    bool **mainMap;
    bool **auxiliaryMap;
    
    int rows;
    int columns;
    int size;//size of cell's home
    
    QColor curCellColor;
    
    bool pause;
    int myTimerId;
    int time;
 
    void setCell(const QPoint &pos, bool alive);//k
 
};
#endif // GAMEMAP_H
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//gamemap.cpp
#include <QtGui>
#include <gamemap.h>
 
#define LEFT_DOWN   mainMap[r + 1][c - 1]                                       ////////////////////////////////////
#define DOWN        mainMap[r + 1][c]                                           //[-1 L_U -1] [-1 U 0] [-1 R_U +1]//
#define RIGHT_DOWN  mainMap[r + 1][c + 1]                                       //[0   L  -1] [0^__^0] [0   R  +1]//
#define RIGHT       mainMap[r][c + 1]                                           //[+1 L_D -1] [+1 D 0] [+1 R_D +1]//
#define RIGHT_UP    mainMap[r - 1][c + 1]                       ////////////////////////////////////
#define UP          mainMap[r - 1][c]
#define LEFT_UP     mainMap[r - 1][c - 1]
#define LEFT        mainMap[r][c - 1]
 
GameMap::GameMap(QWidget *parent) : QWidget(parent)
{
    rows = 100;
    columns = 100;
    
    mainMap = new bool* [rows];
    auxiliaryMap = new bool* [rows];
 
    for(int r = 0; r < rows; ++r)
    {
        mainMap[r] = new bool [columns];
    auxiliaryMap[r] = new bool [columns];
    }
    clearMap();
 
    curCellColor = Qt::black;
    size = 50;
    myTimerId = 0;
    time = 100;
    pause = true;
}
 
GameMap::~GameMap()
{
    for(int r = 0; r < rows; ++r)
    {
        delete[] mainMap[r];
        delete[] auxiliaryMap[r];
    }
    delete[] mainMap;
    delete[] auxiliaryMap;
}
 
QSize GameMap::sizeHint() const
{
    return QSize(columns * size - 1, rows * size - 1);
}
 
void GameMap::paintEvent(QPaintEvent*)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setPen(Qt::black);
    for(int r = 0; r <= rows; ++r)
    painter.drawLine(0, size * r, size * columns, size * r);
    for(int c = 0; c <= columns; ++c)
        painter.drawLine(size * c, 0, size * c, size * rows);
    painter.setBrush(QBrush(curCellColor, Qt::SolidPattern));
    for(int r = 0; r < rows; ++r)
    for(int c = 0; c < columns; ++c)
        if(mainMap[r][c])
    painter.drawEllipse((r * size) + 3, (c * size) + 3, size - 6, size - 6);
}
 
void GameMap::mousePressEvent(QMouseEvent *event)
{
    if(event -> button() == Qt::LeftButton)
        setCell(event -> pos(), true);
    else if(event -> button() == Qt::RightButton)
        setCell(event -> pos(), false);
}
 
void GameMap::mouseMoveEvent(QMouseEvent *event)
{
    if(event -> buttons() & Qt::LeftButton)
        setCell(event -> pos(), true);
    else if(event -> buttons() & Qt::RightButton)
    setCell(event -> pos(), false);
}
 
void GameMap::showEvent(QShowEvent*)
{
    myTimerId = startTimer(time);
}
 
void GameMap::timerEvent(QTimerEvent *event)
{
    if(event -> timerId() == myTimerId)
        step();
    else
    QWidget::timerEvent(event);
}
 
void GameMap::hideEvent(QHideEvent*)
{
    killTimer(myTimerId);
}
 
void GameMap::clearMap()
{
    for(int r = 0; r < rows; ++r)
    for(int c = 0; c < columns; ++c)
        if(mainMap[r][c])
        mainMap[r][c] = 0;
    update();
}
 
 
void GameMap::step()
{
    for(int r = 0; r < rows; ++r)
    for(int c = 0; c < columns; ++c)
    {
        int neighbors = 0;
 
        if((r == 0) && (c == 0))                                            //left up
        neighbors += DOWN + RIGHT_DOWN + RIGHT;
        else if((r == 0) && (c == (columns - 1)))                           //right up
        neighbors += LEFT + LEFT_DOWN + DOWN;
        else if((r == (rows - 1)) && (c == (columns - 1)))                  //right down
        neighbors += UP + LEFT_UP + LEFT;
        else if((r == (rows - 1)) && (c == 0))                              //left down
        neighbors += RIGHT + RIGHT_UP + UP;
        else if(c == 0)                                                     //left
        neighbors += DOWN + RIGHT_DOWN + RIGHT + RIGHT_UP + UP;
        else if(r == 0)                                                     //up
        neighbors += LEFT + LEFT_DOWN + DOWN + RIGHT_DOWN + RIGHT;
        else if(c == (columns - 1))                                         //right
        neighbors += UP + LEFT_UP + LEFT + LEFT_DOWN + DOWN;
        else if(r == (rows - 1))                                            //down
        neighbors += RIGHT + RIGHT_UP + UP + LEFT_UP + LEFT;
        else
        neighbors += LEFT_DOWN + DOWN + RIGHT_DOWN + RIGHT + RIGHT_UP + UP + LEFT_UP + LEFT;
 
            if(mainMap[r][c])
            ((neighbors > 3) || (neighbors < 2)) ? auxiliaryMap[r][c] = false :
                                                       auxiliaryMap[r][c] = true;
        else
        (neighbors == 3) ? auxiliaryMap[r][c] = true :
                                   auxiliaryMap[r][c] = false;
 
        }
 
    for(int r = 0; r < rows; ++r)
        for(int c = 0; c < columns; ++c)
            mainMap[r][c] = auxiliaryMap[r][c];
    update();
}
 
void GameMap::setCell(const QPoint &pos, bool alive)
{
    int     r = pos.x() / size,
        c = pos.y() / size;
    mainMap[r][c] = alive;
    update();
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
#include "gamemap.h"
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    MainWindow(); //k
    ~MainWindow(); //k
    GameMap *map;
 
protected:
    void closeEvent(QCloseEvent *event); //k
 
private slots:
    void newGame(); //k
    /*void openMap();
    bool saveMap();
    bool saveMapAs();*/
    void about(); //k
 
private:
    void createActions(); //k
    void createMenus(); //k
    //void createContextMenu();
    //void createToolBars(); 
    //void createStatusBar();
    //void writeSettings(); 
    //void readSettings(); 
    bool okToContinue(); //k
    //bool loadMap(const QString &fileName);
    //bool saveMap(const QString &fileName);
    //void setCurrentMap(const QString &fileName);
 
    QMenu *fileMenu;
    QMenu *optionsMenu;
    QMenu *helpMenu;
 
    QToolBar *fileToolBar;
 
    QAction *newAction, //k
    //QAction *openAction; //k
    //QAction *saveAction; //k
    //QAction *saveAsAction; //k
    //QAction *closeAction; //k
    QAction     *exitAction; //k
 
 
};
#endif // MAINWINDOW_H
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <QtGui>
#include "mainwindow.h"
#include "gamemap.h"
 
MainWindow::MainWindow()
{
    map = new GameMap;
    setCentralWidget(map);
    createActions();
    createMenus();
    //createContextMenu();
    //createToolBars();
    //createStatusBar();
    //readSettings();
    setWindowIcon(QIcon(":/images/icon.bmp"));
}
 
MainWindow::~MainWindow()
{
    delete map;
    delete newAction;
    delete exitAction;
 
}
 
void MainWindow::newGame()
{
    if(okToContinue())
        map -> clearMap();
 
}
 
void MainWindow::about()
{
    QMessageBox::about(this, tr("About Game of Life"),
                 tr("<h2>Game of Life 0.0.1 (a)</h2>"
                    "<br>All rights reserved. Maybe... :)"));
}
 
void MainWindow::createActions()
{
    newAction = new QAction(tr("&New"), this);
    newAction -> setIcon(QIcon(":images/new.bmp"));
    newAction -> setShortcut(tr("Ctrl + N"));
    newAction -> setStatusTip(tr("Begin a new game"));
    connect(newAction, SIGNAL(triggered()), this, SLOT(newGame()));
 
    /*openAction = new QAction(tr("&Open"), this);
    openAction ->  setIcon(QIvon(":/images/open.bmp"));
    openAction -> setShortcut(tr("Ctrl + O"));
    openAction -> setStatusTip(tr("Open the map"));
    connect(openAction, SIGNAL(triggered()), this, SLOT(openMap()));
    
    saveAction = new QAction(tr("&Save"), this);
    saveAction ->  setIcon(QIvon(":/images/save.bmp"));
    saveAction -> setShortcut(tr("Ctrl + S"));
    saveAction -> setStatusTip(tr("Save the map"));
    connect(saveAction, SIGNAL(triggered()), this, SLOT(saveMap()));
 
    saveAsAction = new QAction(tr("&Save as"), this);
    saveAsAction ->  setIcon(QIvon(":/images/save_as.bmp"));
    saveAsAction -> setStatusTip(tr("Save the map as..."));
    connect(saveAsAction, SIGNAL(triggered()), this, SLOT(saveMapAs()));*/
 
    /*closeAction = new QAction(tr("&Close"), this);
    closeAction -> setShortcut(tr("Ctrl + W"));
    closeAction -> SetStatusTip(tr("Close this map"));
    connect(closeAction, SIGNAL(triggered()), this, SLOT(close()));*/
 
    exitAction = new QAction(tr("E&xit"), this);
    exitAction -> setShortcut(tr("Ctrl + Q"));
    exitAction -> setStatusTip(tr("Exit the application"));
    connect(exitAction, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
}
 
void MainWindow::createMenus()
{
    fileMenu = menuBar() -> addMenu(tr("&File"));
    fileMenu -> addAction(newAction);
    //fileMenu -> addAction(closeAction);
    fileMenu -> addSeparator();
    fileMenu -> addAction(exitAction);
 
    //optionsMenu = menuBar() -> addMenu(tr("&Options"));
    //optionsMenu
}
 
bool MainWindow::okToContinue() //need files
{
    /*for(int row = 0; row < rows; ++row)
        for(int column = 0; column < columns; ++column)
        if(mainMap[row][column])
        {
            int warning = QMessageBox::warning(this, tr("Game of Life"),
                            tr("The map has been modified.\n"
                                "Do you want to save your changes?"),
                                       QMessageBox::Yes | QMessageBox::Default,
                                   QMessageBox::No,
                                   QMessageBox::Cansel | QMessageBox::Escape);
        if(warning == QMessageBox::Yes)
            return saveMap();
        else if(warning == QMessageBox::Cansel)
            return false;
        else
            return true;
            }*/
    return true; //don't remove
}
 
void MainWindow::closeEvent(QCloseEvent *event)
{
    if(okToContinue())
    {
        //writeSettings
        event -> accept();
    }
    else
        event -> ignore();
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <QtGui/QApplication>
#include <QScrollArea>
#include "mainwindow.h"
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
 
    MainWindow *mainW = new MainWindow;
    //QScrollArea *scroll = new QScrollArea;
    //scroll -> setWidget(mainW -> map);
    //scroll -> showMaximized();
    mainW -> showMaximized();
 
    return a.exec();
}
Что я хочу от этого кода. Я хочу, чтобы добавились полосы прокрутки и, чтобы при прокрутке полоса главного меню оставалась на месте. Если убрать комментарии в main, то будет просто поле со скроллбарами, без полоски главного меню(что, в принципе, логично). Если сделать setWidget(mainW), то поле будет прокручиваться вместе с полосой главного меню(что тоже, наверное, предсказуемо). В общем, куда я только не запихивал ScrollArea, нигде она вменяемо работать не хочет.
В процессе тестирования обнаружился неприятный баг. Если прокрутить поле до конца вправо, зажать любую клавишу мыши и сдвинуть мышь до упора вправо, то программа вылетает. Почему так, понять не могу, объясните, пожалуйста, если знаете.
Также буду рад увидеть комментарии по поводу кода.
ps/Большая часть кода не реализована, поскольку без ScrollArea не будет иметь никакого смысла.
Вложения
Тип файла: rar GameOfLife.rar (7.1 Кб, 13 просмотров)
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
06.10.2011, 18:21
Ответы с готовыми решениями:

QScrollArea не вызывает метод QScrollArea::setWidget()
Код с учебника: #include &lt;QtGui&gt; int main(int argc, char* argv) { QApplication app(argc, argv); QScrollArea sa; ...

QScrollArea не прокручивается
QScrollArea не прокручивается! Добавил на QScrollArea QVBoxLayout, на тот QWidget'ы состоящие из 2 QLabel на QVBox. Может что-то не...

Использование QScrollArea
Дорогие форумчане! Пока не нашел ответа на свой вопрос! Подскажите, кто в курсе, что делать. Исходные данные: 1) У меня есть...

1
 Аватар для soon
2554 / 1319 / 178
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
11.10.2011, 15:23  [ТС]
Проблема решена. В конструкторе объявляем QScrollArea, передаем ей QWidget, затем устанавливаем центральный виджет QScrollArea. В данном коде это выглядит так
C++
1
2
3
4
map = new GameMap;
QScrollArea *scroll = new QScrollArea;
scroll -> setWidget(map);
setCentralWidget(scroll);
В main соответственно mainW -> show();
Спасибо всем, кто обращал внимание на тему.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
11.10.2011, 15:23
Помогаю со студенческими работами здесь

QScrollArea не работает
Задача такая: есть много QCheckBox`ов, которые необходимо добавить на QScrollArea. Пробовал делать так: Добавляю QScrollArea, на него кидаю...

Не работает QScrollArea
Здравствуйте, возникла проблема с QScrollArea. В скролл нужно разместить динамически создаваемые виджеты, но, вместо того, что бы...

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

Размер QLabel'a в QScrollArea
Создаю QScrollArea и кидаю в него QLabel. QScrollArea занимает почти все окно, а QLabel наоборот - маленький квадратик. Как увеличить...

Стек виджетов в QScrollArea
Есть класс от QScrollArea, котором есть основной QVBoxLayout, в который как в стек я засовываю одинаковые виджеты. Чем больше этих...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
2
Ответ Создать тему
Новые блоги и статьи
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка библиотек: SDL3, Box2D, FreeType, SDL3_ttf, SDL3_mixer и SDL3_image из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru