[ vs2000 @ 03.04.2011. 12:56 ] @
Imam problem koji se desi kada pokušam da pristupim štampaču u QT-u. Ne uvek, ali možda svaki 10-ti put (otprilike), kada treba da se pokrene štampanje, na redu:
QPrinter printer(QPrinter::HighResolution);

Dođe do greške - Segmentation fault.

Nisam uspeo da zapazim nikakvo pravilo da se to dešava zbog nekog oređenog razloga. Jednostavno se nekada desi, a u većini slučajeva prođe bez problema.
Problem je u tome što program treba da prikuplja podatke jako dugo vremena (oko 12 sati), a zatim da to odštampa. Ako bi se desilo da se program neočiekivano završi na ovom delu svi podaci bi ostali izgubljeni, korisnih bi bio strašno ljut i mogao bi da postane jako opasan, naročito po mene.
Nije šala... U nekom drugom slučaju ovo ne bi bilo baš toliko strašno, ali u ovom jeste. Problem je što je ovo moj prvi program u QT-u, i što imam svega 2 nedelje iskustva sa njim. Pokušao sam da napišem maksimalno pedantno čitav program, ali ovaj problem preti da to sve pokvari.

Drugo pitanje: ima li u QT4 neki način da se nasatavi sa izvršenjem programa ako dođe do ozbiljnog problema, da se preduzme neka radnja predviđena za slučaj greške? Nisam uspeo da nađem odgovor na to. U ovom slučaju ako bi se greška pojavila bih zamoliio korisnika da sačeka trenutak i da ponovo pokuša štampanje, ovako se program samo završi na jako loš način, i podaci nestanu.
try{} catch{} ne funkcioniše, koliko sam shvatio.

Kôd izgleda otprilike ovako:

Code:
void MainWindowImpl::on_action_Stampanje_dijagrama_triggered()  //Meni „Štampanje" stavka „Štampanje dijagrama"
{
    //Kôd za štampanje dijagrama
    QPrinter printer(QPrinter::HighResolution);
    printer.setOrientation(QPrinter::Landscape);
    printer.setPaperSize(QPrinter::A4);
    printer.setOutputFormat(QPrinter::PdfFormat);
    /////printer.setCreator("Moje programče");
    //napraviti fajlić sa vremenom početka merenja u nazivu
    printer.setOutputFileName("/home/vladimir/"+datumPocetkaMerenja.toString("dd-MM-yyyy hh-mm-ss")+".pdf");

    QPainter painter;
    if (! painter.begin(&printer))
    { //Nije mogao biti otvoren fajlić za upisivanje
            qWarning("Nije uspelo upisivanje u fajl. Moguće da je trenutno samo za čitanje");
            return;
    }
    //painter.begin(&printer);

    painter.setFont(QFont("Arial", 8));
    painter.setRenderHint(QPainter::Antialiasing, true);

        QString strTemp;
        strTemp=QString::fromUtf8("NEKI TEKST: ")+lineEditVrstaMaterijala->text();
        painter.drawText(300,200,strTemp);
        strTemp=QString::fromUtf8("JOŠ TEKSTA: ")+lineEditKolicinaMaterijala->text();
        painter.drawText(300,360,strTemp); ///... itd... itd...
        ......

        if(!datumZavrsetkaMerenja.isNull()) //Ako je datum završetka merenja postavljen (pritiskom na STOP
        {                                   //prikazati i njega, inače ne prikazivati ga
            strTemp="JOŠ, JOŠ TEKSTA...: "+datumPocetkaMerenja.toString("dd.MM.yyyy hh:mm:ss")
                    + " - " + datumZavrsetkaMerenja.toString("dd.MM.yyyy hh:mm:ss");
        }
        else
        {
            strTemp="......: "+datumPocetkaMerenja.toString("dd.MM.yyyy hh:mm:ss")
                    + " - ";
        }
        painter.drawText(300,840,strTemp);
 

        //Štampanje dijagrama
        ////QwtPlot *dijagram=new QwtPlot;
        ////QwtPlotGrid *mreza = new QwtPlotGrid;   //crtanje mreže u dijagramu
        ////QwtPlotCurve *referentna_kriva= new QwtPlotCurve("ref.");  //Kriva za referentrnu "crtu"
        QwtPlot dijagram;
        QwtPlotGrid mreza;
        QwtPlotCurve referentna_kriva;

        referentna_kriva.setPen(QPen(Qt::red));
        referentna_kriva.setTitle("ref.temp");
        //referentna_kriva->setPen(QPen(Qt::red));   //boja referentrne crte
        double x_ref[2];    //dve duble promenjive za dve kordinate na početku i na kraju
        double y_ref[2];
       
         ... itd... itd....


        dijagram.setCanvasBackground(QColor(255,255,255));

        //font za dijagram
        QFont font;
        font.setFamily("Helvetica [Cronyx]");
        font.setWeight(QFont::Light);
        font.setPointSize(8);
        dijagram.setAxisFont(QwtPlot::xBottom,font);
        dijagram.setAxisFont(QwtPlot::yLeft,font);
        //legenda
        QwtLegend legenda;
        legenda.setFrameStyle(QFrame::Box|QFrame::Sunken);
        //legenda.setItemMode(QwtLegend::ClickableItem);
        ///legenda.setFont(font);
        dijagram.insertLegend(&legenda, QwtPlot::BottomLegend);

        dijagram.replot();  //primenjivanje svih gornjih podešavanja na dijagram

        QwtPlotRenderer renderer;
        renderer.setDiscardFlag(QwtPlotRenderer::DiscardCanvasBackground);
        //renderer.setLayoutFlag(QwtPlotRenderer::FrameWithScales);

        const QSize sz(12250, 7000);    //postavljanje dimenzija dijagrama
        //crtanje dijagrama određenih dimenzija i na određenoj poziciji
        renderer.render(&dijagram, &painter,  QRectF( QPointF(300, 1200), sz));

        painter.end();  

}   //Kraj funkcije za štampanje dijagrama
[ Nedeljko @ 04.04.2011. 11:31 ] @
Kada ne bih znao gde program puca, ja bih na početku funkcije kreirao fajl (uvek nov sadržaj) i u njega upisivao nešto posle svake naredbe u programu.

Dakle, na početak funkcije bih stavio nešto poput

Code:
ofstream out("crash.log");
out << __LINE__ << endl;


Zaitm bih sva pojavljivanja znaka ";" zamenio sa "; out << __LINE__ << endl;".

E, onda bih znao gde mi program puca u toj funkciji (ako je uopšte u njoj, a ne u njenom pozivanju nešto sa povezivanjem signala i slotova).

Drugo, mnogo bolje rešenje je posmrtno debagovanje. Obzirom da radiš u GNU/Linux okruženju, idi u konzolu i kucaj

ulimit -c unlimited


Onda će ti program nakon pucanja izbaciti trag steka (core fajl na GNU/Linux sistemima), koji će tačno pokazati gde je program pukao. Nakon pucanja (naravno, debug verzije programa) idi u konzolu i kucaj

gdb -c core prog


Neki GNU/Linux sistemi stavljaju neku ekstenziju na core dump tipa core.3641, koja se uvek menja. U tom slučaju, umesto core napiši tačan naziv core dump-a i umesto prog ime izvršnog fajla, sa putanjama ako je potrebno. On će ti pokazati liniju u kojoj je došlo do pucanja.

Kraće uputstvo za gdb:

Da bi video u gdb-u vrednost neke promenljive na mestu gde je program pukao, kucaj "print promenljiva". Da bi video kako se došlo do te funkcije. Kucaj "bt" da bi video frame-ove poziva te funkcije, pa onda "frame broj" da bi ušao u određeni (recimo, da bi tamo ispitao promenljive).
[ vs2000 @ 04.04.2011. 19:32 ] @
Razumem donekle. Ali ja sam već ustanovio na kojem redu je problem. Program nije još u potpunosti završen. Trebaće mi još 10-ak dana, za to vreme ga dovršavam i testiram istovremeno. Red na kojem dolazi do greške je:

QPrinter printer(QPrinter::HighResolution);

Ja program kompajliram još uvek u verziji za ispravljanje greški (debug), i pokrećem u qt kreatoru. Kada se greška desi žuta strelica pokazuje na ovaj red. Ne prođe dalje. I svejedno je da li sam napisao:

Code:
QPrinter printer;


pa u narednom redu:
Code:
printer.setResolution(QPrinter::HighResolution); 


ili mu odmah postavljam da ovo HignResolution, on puca kada se konstruiše QPrinter promenjiva (klasa ili šta već).

Imam rešenje da sve podatke prethodno snimim pre pokretanja ove funkcije, pa ako se desi krah, da pri narednom pokretanju proverim da li nije ostala datoteka koju ću pripremiti za ovakve slučajeve, ali to nije ono što treba da bude krajnje rešenje. Ovde izgleda da je neki problem do qt klase QPrinter.

I da li zna uopšte neko kako da predupredim grešku, da program ne pukne? Zašto ne radi try{} catch{}? Ove komande postoje, ali nemaju nikakvo dejstvo. Ima li neki način da se nešto radi u slučaju fatalne greške, nije valjda da to ne postoji?!
[ Nedeljko @ 05.04.2011. 13:18 ] @
Metodom setResolution podešavaš rezoluciju u DPI jedinicama (broj tačaka po inču, koji daješ kao int), a ne PrinterMode. Takođe, QPrinter::HighResolution je Windows/MacOS X specifičan atribut.

Ako vršiš štampu na papir (dakle, ne u PDF ili PS fajl), onda najpre otvori QPrintDialog da bi korisnik odabrao štampač, pa od njega uzmi QPrinter.