2012-10-01 14 views
5

Ho creato un'app in Qt che contiene due pulsanti: un pulsante di uscita e un pulsante di importazione. Quando viene premuto il pulsante di importazione, viene visualizzato un elenco di pulsanti in una area di scorrimento sullo schermo (il file logger.csv contiene i dati 1; 2; 3; 4; 5;).Esci Applicazione in Qt

Funziona tutto bene, ma quando premo il pulsante di uscita (che ovviamente dovrebbe chiudere tutto), l'applicazione non viene arrestato correttamente (il pulsante di arresto di Qt è ancora attivo, e il pulsante di riproduzione non è). Quando eseguo il debugger e preme il pulsante di uscita, viene visualizzato un errore: indirizzo non valido specificato in RtlFreeHeap (0ADF0000, 0028FE40). Qualcuno può aiutarmi?

principale

#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); 
} 

risposta

6

Non sono del tutto certo su ciò che si sta tentando di raggiungere ... ma il tuo problema è con queste due righe:

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

Nella documentazione per la classe QWidget si afferma che:

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.

Questo è dove si trova il tuo problema. Non credermi, aggiungi questo controllo prima di quelle due righe di codice.

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

Fonte: QVBoxLayout Class Reference

Le linee di classe QVBoxLayout fino widget in verticale.

Questa classe viene utilizzata per costruire oggetti di layout di riquadri verticali. Vedi QBoxLayout per i dettagli.

L'uso più semplice della classe è come questo:

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(); 

In primo luogo, creiamo i widget che vogliamo nel layout. Quindi, creiamo l'oggetto QVBoxLayout e aggiungiamo i widget al layout. Infine, chiamiamo QWidget :: setLayout() per installare l'oggetto QVBoxLayout sul widget. A quel punto, i widget nel layout sono riparati per avere una finestra come genitore.


fonte critica di errore nel progetto:

Widget dovrebbe essere costruita sul mucchio perché saranno automaticamente cancellati quando i loro genitori vengono eliminati. Si dispone di una classe widget personalizzata che si istanzia nell'heap. I membri dovrebbero anche andare sul mucchio. Inoltre, si dovrebbe prendere in considerazione l'utilizzo della gerarchia padre/figlio nel codice della GUI per garantire la corretta gestione della memoria e la corretta eliminazione.

+0

Ok, ma se questo è il caso, in cui si imposta la prima disposizione? Il pulsante di importazione viene solo spinto una volta, quindi non vedo da dove proviene questo primo layout. – Frank

+0

Il pezzo di codice che aggiungi restituisce il layout della finestra principale, no? Se uso 'viewport.layout()' invece di 'layout()', non si accede alla parte qDebug la prima volta che clicco sul pulsante di importazione. – Frank

+0

Leggi le mie modifiche. In particolare l'ultima sezione sui widget e l'allocazione della memoria heap/stack. Spero che ti aiuti. – stackunderflow

1

Nella mia esperienza, se il programma si interrompe in RtlFreeHeap è un buon segno di danneggiamento della memoria.

Quando si chiama

import_btn.setParent(ui->centralWidget); 

centralWidget assume la proprietà di import_btn. Ciò significa che quando viene eliminato centralWidget (che si verifica come parte di delete ui; nel distruttore MainWindow), chiamerà delete nella variabile membro!

Questo porta al danneggiamento della memoria segnalato.

È necessario allocare dinamicamente il valore QPushButton, non come variabile membro normale. Quindi rendili QPushButton*.

+0

Grazie per il suggerimento! Alla fine, il 'import_btn' non era il problema, ma i pulsanti che sono stati importati da questo pulsante. Nel 'logger.h' ho dichiarato un' pulsante * 'con un layout su di esso, e in questo layout un' QLabel num'. Quando ho cambiato questo in un puntatore, i problemi erano spariti. Quindi d'ora in poi userò solo i puntatori nei layout. Grazie a tutti per l'aiuto! – Frank

0

Ecco come ho fatto da mainwindow.cpp, e grazie a questa domanda: 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())); 

funziona perfettamente: D