2012-10-01 112 views
5

我在Qt中構建了一個包含兩個按鈕的應用程序:退出按鈕和導入按鈕。當按下導入按鈕時,屏幕上的滾動區會顯示按鈕列表(文件loggers.csv包含數據1; 2; 3; 4; 5;)。在Qt中退出應用程序

它一切正常,但是當我按下退出按鈕(當然應該關閉所有東西),應用程序沒有正常停止(Qt的停止按鈕仍然活動,並且播放按鈕沒有)。當我運行調試器並按下退出按鈕時,它會發出錯誤:指定給RtlFreeHeap(0ADF0000,0028FE40)的地址無效。有誰能夠幫助我?

#include <QtGui/QApplication> 
#include "mainwindow.h" 

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

    MainWindow w; 

    w.showFullScreen(); 

    return a.exec(); 
} 

Mainwindow.h

#ifndef MAINWINDOW_H 
#define MAINWINDOW_H 

#include <QMainWindow> 
#include <QtGui> 
#include "logger.h" 

namespace Ui { 
class MainWindow; 
} 

class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    explicit MainWindow(QWidget *parent = 0); 
    ~MainWindow(); 

    QPushButton exit_btn; 
    QPushButton import_btn; 

private slots: 

    void createMenus(); 
    void exit(); 
    void import(); 

private: 

    int window_width; 
    int window_height; 

    int numLoggers; 
    int numSelected; 

    QVector<Logger*> loggers; 

    QScrollArea * scroll_area; 

    QVBoxLayout scrollLayout; 

    QWidget viewport; 

    Ui::MainWindow *ui; 
}; 

#endif // MAINWINDOW_H 

Mainwindow.cpp:

#include "mainwindow.h" 
#include "ui_mainwindow.h" 
#include "QtGui" 

MainWindow::MainWindow(QWidget *parent) : 
QMainWindow(parent), 
ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 

    window_width = QApplication::desktop()->width(); 
    window_height = QApplication::desktop()->height(); 

    createMenus(); 

    connect(&exit_btn,SIGNAL(clicked()),this,SLOT(exit())); 
    connect(&import_btn,SIGNAL(clicked()),this,SLOT(import())); 
} 

MainWindow::~MainWindow() 
{ 
    delete ui; 
} 

void MainWindow::createMenus() 
{ 
    import_btn.setParent(ui->centralWidget); 
    import_btn.setGeometry(400,300,100,100); 
    import_btn.setText("IMPORT"); 

    exit_btn.setText("EXIT"); 
    exit_btn.setParent(ui->centralWidget); 
    exit_btn.setGeometry(window_width-50,12,32,32); 

    viewport.setLayout(&scrollLayout); 
    viewport.resize(0,0); 

    scroll_area = new QScrollArea(ui->centralWidget); 
    scroll_area->setGeometry(0,66,317,window_height-116); 
    scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 
    scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 
    scroll_area->setWidget(&viewport); 
    scroll_area->setGeometry(0,97,317,window_height-228); 

    scrollLayout.setMargin(0); 
    scrollLayout.setSpacing(0); 
} 

void MainWindow::exit() 
{ 
    close(); 
    qApp->quit(); 
} 

void MainWindow::import() 
{ 
    numSelected=0; 

    QFile f("Loggers3.csv"); 

    if (f.open(QIODevice::ReadOnly)) 
    { 
     numLoggers=0; 

     QString data; 
     data = f.readAll(); 
     QStringList vals = data.split(';'); 

     while(vals.size()>=1) 
     { 
      Logger * logger = new Logger; 

      logger->setNumber(vals[0].toInt()); 
      vals.removeAt(0); 

      loggers<<logger; 

      numLoggers++; 
     } 
     f.close(); 


     for(int i=0; i<numLoggers;i++) 
     { 
      loggers[i]->createButtons(); 
      scrollLayout.addWidget(loggers[i]->button); 
     } 

     viewport.resize(367,numLoggers*60); 
    } 
} 

logger.h

#ifndef LOGGER_H 
#define LOGGER_H 

#include <QtGui> 

class Logger : public QWidget 
{ 
    Q_OBJECT 
public: 
    explicit Logger(QWidget *parent = 0); 

    ~Logger(); 
    int number; 
    QLabel num; 
    QToolButton * button; 
    bool checked; 

signals: 

public slots: 

    void setNumber(int number); 
    void createButtons(); 
}; 

#endif // LOGGER_H 

logger.cpp

#include "logger.h" 
#include <QtGui> 

Logger::Logger(QWidget *parent) : 
    QWidget(parent) 
{ 
    button = new QToolButton; 
    button->setCheckable(true); 
    button->setMinimumSize(317,60); 
    button->setStyleSheet("QToolButton{background-image: url(images/btn_bg); border:none}"); 
} 

Logger::~Logger() 
{ 
} 

void Logger::setNumber(int logNumber) 
{ 
    number=logNumber; 
} 

void Logger::createButtons() 
{ 
    QLayout * layout = new QHBoxLayout; 

    QSpacerItem *spacer = new QSpacerItem(120, 31, QSizePolicy::Maximum, SizePolicy::Maximum); 

    num.setStyleSheet("color: white; font: bold 16px"); 
    num.setText(QString::number(number)); 

    layout->addWidget(&num); 
    layout->addItem(spacer); 

    button->setLayout(layout); 
} 

回答

6

我不能完全肯定你正在努力實現的是什麼...但你的問題在於以下兩行:

viewport.setLayout(&scrollLayout); 
viewport.resize(0,0); 

在爲QWidget的類的文檔就指出:

If there already is a layout manager installed on this widget, QWidget won't let you install another. You must first delete the existing layout manager (returned by layout()) before you can call setLayout() with the new layout.

這是你的問題所在。不要相信我,在這兩行代碼之前添加此檢查。

if(layout()){ 
     qDebug() << "Another layout exists"; 
    } 

來源:QVBoxLayout Class Reference

的QVBoxLayout類排隊部件垂直。

該類用於構造垂直框佈局對象。有關詳細信息,請參閱QBoxLayout。

類最簡單的用法是這樣的:

QWidget *window = new QWidget; 
QPushButton *button1 = new QPushButton("One"); 
QPushButton *button2 = new QPushButton("Two"); 
QPushButton *button3 = new QPushButton("Three"); 
QPushButton *button4 = new QPushButton("Four"); 
QPushButton *button5 = new QPushButton("Five"); 

QVBoxLayout *layout = new QVBoxLayout; 
layout->addWidget(button1); 
layout->addWidget(button2); 
layout->addWidget(button3); 
layout->addWidget(button4); 
layout->addWidget(button5); 

window->setLayout(layout); 
window->show(); 

首先,我們創建我們要在佈局窗口小部件。然後,我們創建QVBoxLayout對象並將這些小部件添加到佈局中。最後,我們調用QWidget :: setLayout()將QVBoxLayout對象安裝到小部件上。在這一點上,佈局中的小部件將被重新設置爲將窗口作爲它們的父項。在項目中的錯誤


重要來源:

窗口小部件應堆建造,因爲當他們的父母被刪除,他們將被自動刪除。你有一個自定義的小部件類,你在堆上實例化。成員們也應該堆積如山。另外,您應該考慮在GUI代碼中使用父/子層次結構,以確保正確的內存管理和適當的刪除。

+0

好,但如果是這樣的話,我在哪裏設置第一佈局?導入按鈕只被推送一次,所以我不會看到第一個佈局的來源。 – Frank

+0

你添加的那段代碼返回Mainwindow的佈局,不是嗎?如果我使用'viewport.layout()'而不是'layout()',它會在第一次點擊導入按鈕時到達qDebug部分。 – Frank

+0

閱讀我的編輯。特別是關於小部件和堆/棧內存分配的最後部分。希望能幫助你。 – stackunderflow

1

根據我的經驗,如果您的程序停在RtlFreeHeap這是內存損壞的一個好兆頭。

當調用

import_btn.setParent(ui->centralWidget); 

centralWidget需要的import_btn所有權。這意味着,當centralWidget被刪除(這是MainWindow的析構函數中的delete ui;的一部分),它將在您的成員變量上調用delete

這會導致報告的內存損壞。

您需要動態分配您的QPushButton的動態,而不是作爲普通成員變量。所以讓他們QPushButton*

+0

感謝您的提示!最後,'import_btn'不是問題,而是由這個按鈕導入的按鈕。在'logger.h'中,我聲明瞭一個帶有佈局的'button *',並在這個佈局中使用了'QLabel num'。當我將它改爲指針時,問題就消失了。所以從現在開始,我只會在佈局中使用指針。 Thx大家的幫助! – Frank

0

以下是我從mainwindow.cpp做到了,這要歸功於這個問題:How to create a correct exit button in qt

QPushButton * quit_btn = new QPushButton(this); 
quit_btn->setGeometry(540,440,93,27); 
quit_btn->setText("Exit"); 
QObject::connect(quit_btn,SIGNAL(clicked()),qApp,SLOT(quit())); 

完美的作品:d