• 12199阅读
  • 9回复

能否帮忙看找一下问题的原因,我实在想不出办法了 [复制链接]

上一主题 下一主题
离线睡眠抱
 
只看楼主 倒序阅读 楼主  发表于: 2007-08-22
— 本帖被 XChinux 执行加亮操作(2007-08-22) —
初学QT,也一直在做一个用于嵌入式的数据采集显示的程序,自己用QFrame子类化一个用于画曲线的类Screen,能实时移动的窗口部件,当QWidget上只放一个Screen的时候,画图还正常的,当放2个或3个的时候就不正常了,而且不正常的情况还不一样,而我需要放三个,想了一天了也想不出原因,特来向大家请教一下,帮忙找找原因。下面我将程序,运行的截图,和问题一一说明:
这个是父窗口部件,其他部件都将放在他上面:
#ifndef DISPLAY_H
#define DISPLAY_H

#ifndef QT_H
#include <qwidget.h>
#endif // QT_H

class QTimer;
class Screen;
class QStringList;
class QString;
class QLineEdit;
class QPushButton;

class DisplayWidget : public QWidget {
    Q_OBJECT
public:
    DisplayWidget( QWidget *parent=0, const char *name=0 );

    QSize sizeHint() const;
        double readCurveDate();
        void readFile();
    void run();
protected:
        //virtual void showEvent ( QShowEvent * );
private slots:
    void tick();
        void start();
        void stop();

private:
    Screen *screen1;
        Screen *screen2;
        Screen *screen3;
 
        QLineEdit *lineEdit;
        QPushButton *startButton, *stopButton;
                QTimer *timer;
                enum { Margin = 40};       
        QString str;
        QStringList strlist;
        QStringList ::Iterator it;
        int time;
        double yval;
};

#endif // PLOT_H
他的实现:
#include "display.h"
#include "screen.h"

#include <qlayout.h>
#include <qtimer.h>
#include <qframe.h>
#include <qlineedit.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qpushbutton.h>
#include <qfile.h>
//#include <cstdlib>
#include <iostream>
using namespace std;


DisplayWidget::DisplayWidget( QWidget *parent, const char *name )
    : QWidget( parent, name )
{
    timer = 0;

    QVBoxLayout *vbox = new QVBoxLayout( this, 10 );

    QHBoxLayout *hbox = new QHBoxLayout( vbox );
    screen1 = new Screen( this );
        screen1->setYTitle( QObject::tr( "Vlure 1" ) );
        screen2 = new Screen( this );
        screen2->setYTitle( QObject::tr( "Vlure 2" ) );
        screen3 = new Screen( this );
        screen3->setYTitle( QObject::tr( "Vlure 3" ) );
                vbox->addWidget( screen1 );
        vbox->addWidget( screen2 );
        vbox->addWidget( screen3 );
        lineEdit = new QLineEdit(this);
        lineEdit->setReadOnly( TRUE );
        hbox->addWidget( lineEdit );


        startButton = new QPushButton( this );
        startButton->setText( tr( "&Start" ) );
    startButton->setAccel( QKeySequence( tr( "Alt+S" ) ) );
        stopButton = new QPushButton( this );
        stopButton->setText( tr( "Sto&p" ) );
    stopButton->setAccel( QKeySequence( tr( "Alt+P" ) ) );
        hbox->addWidget( startButton );
        hbox->addWidget( stopButton );
        connect( startButton, SIGNAL( clicked () ), SLOT( start() ) );
        connect( stopButton, SIGNAL( clicked () ), SLOT( stop() ) );
        time = 0;
        yval = 0.0;
        readFile();
}
void DisplayWidget::run()
{
    if ( !timer ) {
        timer = new QTimer( this );
        connect( timer, SIGNAL( timeout() ), SLOT( tick() ) );
    }

    timer->start( 1000 );
}


void DisplayWidget::tick()
{
        yval = readCurveDate();
            screen1->animate( yval );
        screen2->animate( yval );
        screen3->animate( yval );
        lineEdit->setText( QString::number( yval ) );
}

void DisplayWidget::start()
{
        run();
}
void DisplayWidget::stop()
{
        timer->stop();
}

QSize DisplayWidget::sizeHint() const
{
        return QSize( 16 * Margin, 12 * Margin );
}
//下面两个成员函数是用于将模拟数据从in.txt中读出用于显示
void DisplayWidget::readFile()
{
        QFile file("in.txt");
        file.open(IO_ReadOnly);
        QTextStream in(&file);       
        str = in.read();
        strlist = QStringList::split(" ", str);
        it = strlist.begin();       
}
double DisplayWidget::readCurveDate( )
{
        QString tempStr;
        double tempDate;
       

        tempStr =(QString) *it;
        tempDate = tempStr.toDouble();
       
        if (it != strlist.end())
        {       
                ++it;
                //cerr<<"time=108"<<endl;       
        }
        else
        {
                it = strlist.begin();
                //cerr<<"time=109"<<endl;       
        }
        //cerr<<"curveDate ="<<tempDate<<endl;
        return tempDate;
}
下面这个是用于画图的类,也是最做要的地方:
#ifndef SCREEN_H
#define SCREEN_H

#include <qframe.h>
#include <qvaluevector.h>
#include <qpixmap.h>
#include <qpainter.h>

#define FrameWidth                3
#define Step                5  //一次移动的时候的长度,五个像素
#define BaseFontHeight        20
#define BaseLineLenght        5 //画刻度的单位长度
#define SpaceMargin                5


class QRect;
class QString;

class Screen : public QFrame {
        Q_OBJECT
public:
        Screen( QWidget *parent=0, const char *name=0, WFlags flags=0 );
        void animate( double y);
        void setXTitle( QString &str );
        void setYTitle( QString &str );
protected:
          void initNumber( void );
          void initCordinate( QPainter &p );
        void updateCurve( QPainter &p );
        virtual void showEvent ( QShowEvent * );
        virtual void hideEvent ( QHideEvent * );
        QSize minimumSize () const;
public: 
        double newY, oldY;
        int numXTicks, numYTicks;
        QValueVector< double > Yval;
        bool firstShow;
        int sec, min, hour;
        QPixmap saveBuffer, newBuffer, midBuffer;
        QRect rectCordinate;
        QRect fromSaveRect;
        QRect toNewRect;
        QRect rectYText;
        QRect rectXText;
        /*We use this painter to draw evering on the newbuffer.*/
        QPainter drawPainter;
        QString stringYTitle;
        QString stringXTitle;
};
#endif /*SCREEN_H*/
他的实现:
#include "screen.h"

#include <qevent.h>
#include <qrect.h>
#include <qsize.h>
#include <qstring.h>
#include <iostream>
using namespace std;
#include <qwmatrix.h>
#include <qfont.h>
#include <qpen.h>

Screen::Screen(  QWidget *parent, const char *name, WFlags flags )
    : QFrame( parent, name, flags | WNoAutoErase ) 
{
        setLineWidth( FrameWidth );       
        setFrameStyle( Panel | Sunken );
        setBackgroundMode( PaletteBase );       
        setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding );
        firstShow = TRUE;
       
}

void Screen::showEvent( QShowEvent *e )
{
        if ( firstShow )
                initNumber();
        initCordinate( drawPainter );
}

QSize Screen::minimumSize () const
{
        return QSize( 20 * SpaceMargin,  20 * SpaceMargin );
}

void Screen::hideEvent( QHideEvent *e )
{
        firstShow = FALSE;
}

void Screen::setXTitle(        QString &str )
{
        stringXTitle = str;
}
void Screen::setYTitle( QString &str )
{
        stringYTitle = str;
}
void Screen::initNumber( )
{
        saveBuffer.resize( size() );   
        saveBuffer.fill( this, 0, 0 );               
        newBuffer.resize( size() );
        newBuffer.fill( this, 0, 0 );
        midBuffer.resize( size() );
        midBuffer.fill( this, 0, 0 );
       
        drawPainter.begin(&newBuffer);
        QRect newWindow = drawPainter.window();

        newY = 0;
        oldY =0;

        sec = 0;
        min = 0;
        hour = 0;
       
        stringXTitle = QObject::tr( "Time (hh:mm:ss)" );
        Yval.push_back( (double)oldY );
              /*曲线要在下面这个矩形里面*/
        rectCordinate.setRect(
                        newWindow.topLeft().x()+FrameWidth + 2 * BaseFontHeight + 2 * BaseLineLenght,
                newWindow.topLeft().y()+FrameWidth + 2 * SpaceMargin,
                newWindow.width() - 2 * ( FrameWidth + BaseFontHeight + BaseLineLenght + SpaceMargin ),
                newWindow.height() - 2 * ( FrameWidth + BaseFontHeight + BaseLineLenght + SpaceMargin ) );
                /*下面这几步是让矩形的高和宽变成5个像素的倍数,是为了好看点*/
        if ( 0 != ( rectCordinate.width() % (Step*Step) ) )
        {
                int x = rectCordinate.width() % ( Step * Step );        //( (int) sqrt( (float) Step ) );
                rectCordinate.setWidth( rectCordinate.width() - x+1 );
        }

        if ( 0 != ( rectCordinate.height() % (Step*Step) ) )
        {
                int y = rectCordinate.height() % (Step*Step);                                rectCordinate.setHeight( rectCordinate.height() - y+1 );
        }
        numXTicks = rectCordinate.width() / Step;
        numYTicks = rectCordinate.height() / Step;
                /*rectYText是用写y轴标题的矩形范围*/
        rectYText.setRect(
                        newWindow.topLeft().x() + FrameWidth,
                        newWindow.topLeft().y() + FrameWidth + 2 * SpaceMargin,
                        BaseFontHeight, rectCordinate.height() );
                /*rectXText是用写x轴标题的矩形范围*/
        rectXText.setRect(
                rectCordinate.bottomLeft().x(),
                newWindow.bottomLeft().y() - FrameWidth - BaseFontHeight,
                rectCordinate.width(), BaseFontHeight );
                /*fromSaveRect和toNewRect是用来剪切三张QPixmap上曲线的范围的矩形大小,可以显示曲线与坐标的移动*/
        fromSaveRect.setRect(
                rectCordinate.topLeft().x() + Step,
                rectCordinate.topLeft().y() + 1,
                rectCordinate.width() - Step - 1,
                rectCordinate.height() + 2 * BaseLineLenght + BaseFontHeight );
        toNewRect.setRect(
                rectCordinate.topLeft().x() + 1,
                rectCordinate.topLeft().y() + 1,
                rectCordinate.width() - Step - 1,
                rectCordinate.height() + 2 * BaseLineLenght + BaseFontHeight );
        drawPainter.drawRect(toNewRect);
               
}

void Screen::initCordinate( QPainter &pCordinate )/初始化坐标系
{
  if ( firstShow )
  {       
        pCordinate.setPen( Qt::blue );
        pCordinate.drawRect( rectCordinate );
       
        /*画y轴的刻度、坐标值和标题*/
        int y0 = rectCordinate.bottomLeft().y();
        int x0 = rectCordinate.bottomLeft().x();
        int yText = 0;
        int xText= 0;
        for (int j = 0; j <= numYTicks; j ++ )
        {
                pCordinate.drawLine( x0 - BaseLineLenght, y0, x0, y0 );
                if (0 == j % Step )
                {
                        pCordinate.drawLine( x0 - 2 * BaseLineLenght, y0, x0 - BaseLineLenght, y0 );
                        pCordinate.save();
                        pCordinate.setPen( QPen( blue, 1, DotLine) );
                        pCordinate.drawLine( x0 , y0, rectCordinate.bottomRight().x(), y0 );
                        pCordinate.restore();
                        pCordinate.setPen( Qt::black );

                       
                        pCordinate.drawText(
                                x0 - 2 * BaseLineLenght - BaseFontHeight,
                                y0 - 2 * BaseFontHeight + 5 * Step,
                                BaseFontHeight, BaseFontHeight + Step,
                                AlignCenter , QString::number( yText) );
                                yText ++;
                        pCordinate.setPen( Qt::blue );
                }
                y0 -= Step;
        }
       
        /*画y轴的标题*/
        pCordinate.save();

        QRect tempYText(
                rectYText.topLeft().x(), rectYText.topLeft().y(),
                rectYText.height(), rectYText.height() );
        pCordinate.setViewport( tempYText );
        QRect rectYViewport = pCordinate.viewport();
        pCordinate.setWindow( -(int)rectYViewport.width()/2, -(int)rectYViewport.height()/2,
        rectYViewport.width(), rectYViewport.height() );
        QRect rectYWindow = pCordinate.window();
        QRect rectDrawText(
                rectYWindow.topLeft().x(),
                -(int)rectYText.width()/2,
                rectYText.height(),
                rectYText.width() );
        pCordinate.rotate(-90.0);
        double dy = ( rectYWindow.width() - rectDrawText.height() ) / 2;
        dy = dy > 0 ? dy : ( -dy );
        pCordinate.translate( 0, -dy );
        pCordinate.drawText(
                rectDrawText.topLeft().x(),
                rectDrawText.topLeft().y(),
                rectDrawText.width(),
                rectDrawText.height(),
                AlignCenter, stringYTitle );
        pCordinate.restore();

        /*画x轴的刻度和标题*/
        pCordinate.setPen( Qt::blue );
        y0 = rectCordinate.bottomLeft().y();
        for ( int i = 0; i <= numXTicks; i ++ )
        {
                pCordinate.drawLine( x0 , y0, x0, y0 + BaseLineLenght );
                if ( 0 == i % (2*Step) )
                {
                    pCordinate.save();
                    pCordinate.setPen( QPen( blue, 1, DotLine) );
                    pCordinate.drawLine( x0 , rectCordinate.bottomLeft().y(),
                    x0 , rectCordinate.topLeft().y() );
                    pCordinate.restore();
                }

                x0 += Step;
        }
       
        /*画x轴的标题*/
        pCordinate.drawText(
                              rectXText.topLeft().x(), rectXText.topLeft().y(),
                      rectXText.width(), rectXText.height(),
                      AlignCenter, stringXTitle );
                       
  }
        /*将初始化好的坐标系复制到Screen部件上*/
          bitBlt( this, 0, 0, &newBuffer, 0, 0, newBuffer.width(), newBuffer.height() );
       
}



void Screen::animate( double y )
{
       
        newY = y;
        if ( (int) Yval.size() <= (int) width() / 4 )
        {
                Yval.append( newY );
        } else {
                Yval.erase( Yval.begin() );
                Yval.append( newY );
        }
       
        updateCurve( drawPainter);

}
/*更新曲线,实现曲线和坐标的移动*/
void Screen::updateCurve( QPainter &pDrawCurve)
{
/*设计思路:三个QPixmap,其中newBuffer是用于画图和复制给Screen的,saveBuffer是用于保存上次newBuffer,midBuffer从saveBuffer中将需要往前移动的部分剪切到自己上面,最后newBuffer从midBuffer上将移动的部分加上需要的空白复制到自己绘图矩形内,实现了曲线和坐标向前移动,最后在空白出画上最新的坐标,曲线和时间*/
        copyBlt ( &saveBuffer, 0, 0,&newBuffer, 0, 0, newBuffer.width(), newBuffer.height() );
        copyBlt ( &midBuffer, toNewRect.topLeft().x(), toNewRect.topLeft().y(),
                            &saveBuffer, fromSaveRect.topLeft().x(), fromSaveRect.topLeft().y(),
                    fromSaveRect.width(), fromSaveRect.height() );
        copyBlt ( &newBuffer, rectCordinate.topLeft().x()+1, rectCordinate.topLeft().y()+1,
                    &midBuffer, rectCordinate.topLeft().x()+1, rectCordinate.topLeft().y()+1,
                      rectCordinate.width()-2, fromSaveRect.height() );
       

        QValueVector<double>::iterator Yit = Yval.end();
        double Ynew, Yold;
        int Xnew, Xold;
        Ynew = rectCordinate.bottomRight().y() - *(--Yit) - 1;
        Xnew = rectCordinate.bottomRight().x() -1;
        Yold = rectCordinate.bottomRight().y() - *(--Yit) - 1;
        Xold = rectCordinate.bottomRight().x() - Step;
       
       
       
        /*画移动后空白处的横坐标和刻度*/
        pDrawCurve.setPen( Qt::blue );
        pDrawCurve.drawLine(
                toNewRect.bottomRight().x(), rectCordinate.bottomRight().y(),
                rectCordinate.bottomRight().x(), rectCordinate.bottomRight().y() );                pDrawCurve.drawLine(               
                toNewRect.bottomRight().x(), rectCordinate.bottomRight().y(),
                toNewRect.bottomRight().x(), rectCordinate.bottomRight().y() + BaseLineLenght );
       
        /*draw the dotline in the horizontal direction*/
        int y0 = rectCordinate.bottomRight().y();
        static bool drawDotLine = FALSE;
        pDrawCurve.save();
        if ( drawDotLine )
        {
                for (int j =0; j < (numYTicks /5 -1 ); j++)
                {
                      y0 -= 5*Step;
                    pDrawCurve.setPen( QPen( blue, 1, DotLine) );
                    pDrawCurve.drawLine( toNewRect.bottomRight().x() , y0,
                            rectCordinate.bottomRight().x(), y0 );
                }
        }
        pDrawCurve.restore();
        drawDotLine = !drawDotLine;

        /*draw the calibration values of x-axis*/
        static int numX = 0;
        if ( 0 == numX % (2*Step) )
        {
                /*以hh:mm:ss的格式画时间*/
                int low = hour % 10;
                int high = hour / 10;
                QString timeString;       
                timeString += ( QString( "%1%2:").arg(high).arg(low) );
                low = min % 10;
                high = min / 10;
                timeString += ( QString( "%1%2:").arg(high).arg(low) );
                low = sec % 10;
                high = sec / 10;
                timeString += ( QString( "%1%2").arg(high).arg(low) );               

                /*draw the long calibration */
                pDrawCurve.drawLine(
                        toNewRect.bottomRight().x(),
                        rectCordinate.bottomRight().y() + BaseLineLenght,
                        toNewRect.bottomRight().x(),
                        rectCordinate.bottomRight().y() + 2 * BaseLineLenght );

                /*draw the dotline in the vertical direction*/
                pDrawCurve.save();
                pDrawCurve.setPen( QPen( blue, 1, DotLine) );
                pDrawCurve.drawLine(
                        toNewRect.bottomRight().x(),
                        rectCordinate.bottomRight().y(),
                        toNewRect.topRight().x(),
                        rectCordinate.topRight().y() );
                pDrawCurve.restore();
       
                /*draw the calibration values of x-axis*/
                if ( 0 == numX % (4*Step) )
                {
                      pDrawCurve.drawLine(
                        toNewRect.bottomRight().x(),
                        rectCordinate.bottomRight().y() + 2*BaseLineLenght,
                        toNewRect.bottomRight().x(),
                        rectCordinate.bottomRight().y() + 3 * Step );
                       
                    pDrawCurve.setPen( Qt::black );
                                /*画时间的矩形范围*/
                    QRect rectCValue(
                        toNewRect.bottomRight().x() - 9 * Step,
                        toNewRect.bottomRight().y() - BaseFontHeight+2,
                        10 * Step,
                        BaseFontHeight);
                    pDrawCurve.drawText(
                        rectCValue.topLeft().x(),
                        rectCValue.topLeft().y(),
                        rectCValue.width(),
                                rectCValue.height(),
                        AlignRight | Qt::AlignHCenter,
                        timeString );
                }
                sec += 10;
                if ( 60 == sec )
                {
                        sec = 0;
                        min += 1;
                        if ( 60 == min )
                        {
                                min = 0;
                                hour += 1;
                                if ( 60 == hour )
                                        hour = 0;
                        }
                }
               

        }
        numX ++;
        if ( numX >= 100 )
                numX = 0;
       

        /*更新曲线,便且将曲线复制到Screen上显示*/
        pDrawCurve.setPen( Qt::black );
        pDrawCurve.drawLine( Xold, (int)Yold, Xnew, (int)Ynew );
        bitBlt( this, 0, 0, &newBuffer, 0, 0, newBuffer.width(), newBuffer.height() );
       
}
碰到的问题有下面几个:
第一:如图一所示刚运行的时候不能显示我在Screen::initCordinate( QPainter &pCordinate )里初始化的图,只有当按了Start后才能显示,(我在Screen::showEvent( QShowEvent *e )里初始化变量和坐标系,是因为我在构造函数中初始化的时候调用width()和height()的时候值是负的,显然不对)原来我timer是在构造函数的最后开始自动运行的时候就可以?

第二:如剩余的图所示,我只放一个Screen的时候还好的,这也是我要的结果,但放两个的时候就出错了,很多都没有画出来而且上面的那个刻度间隔也不对,我是以20个为一个单位。放三个的时候screen1是对的,但screen2和screen3的坐标值和刻度都错了,为什么同一个类会出现这种情况??

我实在是找不出原因,只好求救于大家,希望能指导一下小弟,不胜感激
离线XChinux

只看该作者 1楼 发表于: 2007-08-22
难用QGraphicsView、QGraphicsScene这些东西么?
对这方面不可了解。
二笔 openSUSE Vim N9 BB10 XChinux@163.com 网易博客 腾讯微博
承接C++/Qt、Qt UI界面、PHP及预算报销系统开发业务
离线睡眠抱
只看该作者 2楼 发表于: 2007-08-23
因为我用的是QT3.2.1的 也就是以齐亮翻译的那本书作为参考书的
离线snow_man_0

只看该作者 3楼 发表于: 2007-08-23
做一个PLOT类专门显示曲线,更新的算法是擦除原来的图形,改变数据和坐标,重画一遍
离线睡眠抱
只看该作者 4楼 发表于: 2007-08-24
已解决第二个问题 因为我在updateCurve用了static变量 这会影响整个类的成员的
第一个还没解决
离线wzc81614
只看该作者 5楼 发表于: 2008-07-03
为什么你读取的数据和你的坐标上的数据不能对应起来啊!?
离线0603136
只看该作者 6楼 发表于: 2008-09-09
想问一下这个程序怎么运行?
谢谢。这个帖子很长时间了,也希望知道的朋友给说一下
呵呵,我自信
离线x-planet

只看该作者 7楼 发表于: 2008-11-10
关注中
离线l57164071
只看该作者 8楼 发表于: 2009-02-13
谢谢楼主的例子~~我虽然没找到楼主的解决方法,但是我解决了我的问题~~~
离线gaochengbing
只看该作者 9楼 发表于: 2009-06-08
你好  我也编了一个跟你同样的程序  但是我一按下start就出现了A Painter device can only be painted  by one painter at a time  希望大家能帮忙解决一下 谢了
快速回复
限100 字节
 
上一个 下一个