⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 grapher.cpp

📁 Qt/Embedded是一个多平台的C++图形用户界面应用程序框架
💻 CPP
字号:
// Include Qt Netscape Plugin classes.#include "qnp.h"// Include other Qt classes.#include <qpainter.h>#include <qtextstream.h>#include <qbuffer.h>#include <qpixmap.h>#include <qmenubar.h>#include <qpushbutton.h>#include <qlist.h>#include <qmessagebox.h>// Include some C library functions.#include <math.h>#include <stdlib.h>#ifndef M_PI // Some math.h don't include this.#define M_PI 3.14159265358979323846264338327950288#endif//// GraphModel is a simple abstract class that describes// a table of numeric and text data.//class GraphModel {public:    enum ColType { Numeric, Label };    union Datum {	double dbl;	QString* str;    };    virtual QList<Datum>& graphData()=0;    virtual ColType colType(int col) const=0;    virtual int nCols() const=0;};//// Graph is a widget subclass that displays a GraphModel.// Since the widget is a QNPWidget, it can be used as a plugin window,// returned by Grapher::newWindow() below.//class Graph : public QNPWidget {    Q_OBJECTpublic:    // Constructs a Graph to display a GraphModel    //    Graph(GraphModel&);    ~Graph();    // Two styles are available - Pie and Bar graph    //    enum Style { Pie, Bar };    static const char* styleName[];    void setStyle(Style);    void setStyle(const char*);    // Timer event processing rotates the pie graph    //    void timerEvent(QTimerEvent*);    // These functions are provided by QNPWidget - we override    // them to hide and show the plugin menubar.    //    void enterInstance();    void leaveInstance();    // Paint the graph...    //    void paintEvent(QPaintEvent*);    //    // ... as either a "Loading" message, a Bar graph, a Pie graph,    // or an error message.    //    void paintWait(QPaintEvent*);    void paintBar(QPaintEvent*);    void paintPie(QPaintEvent*);    void paintError(const char*);signals:    // Signals emitted when the Help menus are selected.    void aboutPlugin();    void aboutData();private:    GraphModel& model;    QMenuBar *menubar;    Style style;    QPopupMenu* stylemenu;    int pieRotationTimer;    int pieRotation;    QPixmap pm;private slots:    void setStyleFromMenu(int id);};Graph::Graph( GraphModel& mdl ) :    model(mdl),    style(Bar),    pieRotationTimer(0),    pieRotation(0){    // Create a menubar for the widget    //    menubar = new QMenuBar( this );    stylemenu = new QPopupMenu;    stylemenu->setCheckable(TRUE);    for ( Style s = Pie; styleName[s]; s = Style(s+1)) {	stylemenu->insertItem(styleName[s], s+100);    }    connect(stylemenu, SIGNAL(activated(int)),	this, SLOT(setStyleFromMenu(int)));    setStyle(Pie);    menubar->insertItem("Style", stylemenu);    menubar->insertSeparator();         QPopupMenu* help = new QPopupMenu;    help->insertItem( "About plugin...", this, SIGNAL(aboutPlugin()) );    help->insertItem( "About data...", this, SIGNAL(aboutData()) );    menubar->insertItem("Help", help);}Graph::~Graph(){}void Graph::setStyle(Style s){    if (style != s) {	if (pieRotationTimer)	    killTimer(pieRotationTimer);	stylemenu->setItemChecked(100+style, FALSE);	style = s;	if ( style == Pie )	    pieRotationTimer = startTimer( 80 );	else	    pieRotationTimer = 0;	stylemenu->setItemChecked(100+style, TRUE);	update();    }}void Graph::timerEvent(QTimerEvent*){    pieRotation = ( pieRotation + 6 ) % 360; repaint(FALSE);}void Graph::setStyle(const char* stext){    for ( Style s = Pie; styleName[s]; s = Style(s+1) ) {	if ( qstricmp(stext,styleName[s])==0 ) {	    setStyle(s);	    return;	}    }}void Graph::enterInstance(){    menubar->show();}void Graph::leaveInstance(){    menubar->hide();}void Graph::paintError(const char* e){    QPainter p(this);    int w = width();    p.drawText(w/8, 0, w-w/4, height(), AlignCenter|WordBreak, e);}void Graph::paintBar(QPaintEvent* event){    if ( model.colType(0) != GraphModel::Numeric ) {	paintError("First column not numeric, cannot draw bar graph\n");	return;    }    QList<GraphModel::Datum>& data = model.graphData();    double max = 0.0;    for (GraphModel::Datum* rowdata = data.first();	rowdata; rowdata = data.next())    {	if (rowdata[0].dbl > max) max = rowdata[0].dbl;    }    const uint w = width();    const uint h = height();    QPainter p(this);    p.setClipRect(event->rect());    if ( w > data.count() ) {	// More pixels than data	int x = 0;	int i = 0;	QFontMetrics fm=fontMetrics();	int fh = fm.height();	for (GraphModel::Datum* rowdata = data.first();	    rowdata; rowdata = data.next())	{	    QColor c;	    c.setHsv( (i * 255)/data.count(), 255, 255 );// rainbow effect	    p.setBrush(c);	    int bw = (w-w/4-x)/(data.count()-i);	    int bh = int((h-h/4-1)*rowdata[0].dbl/max);	    p.drawRect( w/8+x, h-h/8-1-bh, bw, bh );	    if (model.colType(1) == GraphModel::Label) {		p.drawText(w/8+x, h-h/8, bw, fh+h/8,		    WordBreak|AlignTop|AlignHCenter,		    *rowdata[1].str);	    }	    i++;	    x+=bw;	}    } else {	// More data than pixels	int x = 0;	int i = 0;	double av = 0.0;	int n = 0;	for (GraphModel::Datum* rowdata = data.first(); rowdata;	    rowdata = data.next())	{	    int bx = i*w/data.count();	    if (bx > x) {		QColor c;		c.setHsv( (x * 255)/w, 255, 255 );// rainbow effect		p.setPen(c);		int bh = int(h*av/n/max);		p.drawLine(x,h-1,x,h-bh);		av = 0.0;		n = 0;		x = bx;	    }	    av += rowdata[0].dbl;	    n++;	    i++;	}    }}void Graph::paintPie(QPaintEvent* event){    if ( model.colType(0) != GraphModel::Numeric ) {	paintError("First column not numeric, cannot draw pie graph\n");	return;    }    QList<GraphModel::Datum>& data = model.graphData();    double total = 0.0;    GraphModel::Datum* rowdata;    for (rowdata = data.first();	rowdata; rowdata = data.next())    {	total += rowdata[0].dbl;    }    // Only use first column for pie chart    if ( !total ) return;    int apos = (pieRotation-90)*16;    const int w = width();    const int h = height();    const int xd = w - w/5;    const int yd = h - h/5;    pm.resize(width(),height());    pm.fill(backgroundColor());    QPainter p(&pm);    p.setFont(font());    p.setClipRect(event->rect());    int i = 0;    for (rowdata = data.first();	rowdata; rowdata = data.next())    {	QColor c;	c.setHsv( ( i * 255)/data.count(), 255, 255 );// rainbow effect	p.setBrush( c );			// solid fill with color c	int a = int(( rowdata[0].dbl * 360.0 ) / total * 16.0 + 0.5);	p.drawPie( w/10, h/10, xd, yd, -apos, -a );	apos += a;	i++;    }    if (model.colType(1) == GraphModel::Label) {	double apos = (pieRotation-90)*M_PI/180;	for (rowdata = data.first();	    rowdata; rowdata = data.next())	{	    double a = rowdata[0].dbl * 360 / total * M_PI / 180;	    int x = int(cos(apos+a/2)*w*5/16 + w/2 + 0.5);	    int y = int(sin(apos+a/2)*h*5/16 + h/2 + 0.5);	    p.drawText(x-w/8, y-h/8, w/4, h/4,		WordBreak|AlignCenter,		*rowdata[1].str);	    apos += a;	}    }    QPainter p2(this);    p2.setClipRect(event->rect());    p2.drawPixmap(0,0,pm);}void Graph::paintWait(QPaintEvent*){    QPainter p(this);    p.drawText(rect(), AlignCenter, "Loading...");}void Graph::paintEvent(QPaintEvent* event){    if (!model.nCols()) {	paintWait(event);    } else {	switch (style) {	  case Pie:	    paintPie(event);	    break;	  case Bar:	    paintBar(event);	    break;	}    }}void Graph::setStyleFromMenu(int id){    setStyle(Style(id-100));}const char* Graph::styleName[] = { "Pie", "Bar", 0 };//// Grapher is a subclass of QNPInstance, and so it can be returned// by GrapherPlugin::newInstance().  A QNPInstance represents the// plugin, distinctly from the plugin window.//// Grapher is also a GraphModel, because it loads graph data from// the net.  When Grapher creates a window in newWindow(), it creates// a Graph widget to display the GraphModel that is the Grapher itself.//class Grapher : public QNPInstance, GraphModel {    Q_OBJECTpublic:    // Create a Grapher - all Grapher plugins are created    // by one GrapherPlugin object.    //    Grapher();    ~Grapher();    // We override this QNPInstance function to create our    // own subclass of QNPWidget, a Graph widget.    //    QNPWidget* newWindow();    // We override this QNPInstance function to process the    // incoming graph data.    //    int write(QNPStream* /*str*/, int /*offset*/, int len, void* buffer);private:    // Grapher is a GraphModel, so it implements the pure virtual    // functions of that class.    //    QList<Datum>& graphData();    ColType colType(int col) const;    int nCols() const;    void consumeLine();    QList<Datum> data;    QBuffer line;    bool firstline;    int ncols;    ColType *coltype;private slots:    // Slots that are connected to the Graph menu items.    //    void aboutPlugin();    void aboutData();};Grapher::Grapher(){    data.setAutoDelete(TRUE);    firstline = TRUE;    ncols = 0;    line.open(IO_WriteOnly|IO_Truncate);}Grapher::~Grapher(){}QList<GraphModel::Datum>& Grapher::graphData(){    return data;}GraphModel::ColType Grapher::colType(int col) const{    return coltype[col];}int Grapher::nCols() const{    return ncols;}QNPWidget* Grapher::newWindow(){    // Create a Graph - our subclass of QNPWidget.    Graph *graph = new Graph(*this);    // Look at the arguments from the EMBED tag.    //   GRAPHSTYLE chooses pie or bar    //   FONTFAMILY and FONTSIZE choose the font    //    const char* style = arg("GRAPHSTYLE");    if ( style ) graph->setStyle(style);    const char* fontfamily = arg("FONTFAMILY");    const char* fontsize = arg("FONTSIZE");    int ptsize = fontsize ? atoi(fontsize) : graph->font().pointSize();    if (fontfamily) graph->setFont(QFont(fontfamily, ptsize));    connect(graph, SIGNAL(aboutPlugin()), this, SLOT(aboutPlugin()));    connect(graph, SIGNAL(aboutData()), this, SLOT(aboutData()));    return graph;}void Grapher::consumeLine(){    line.close();    line.open(IO_ReadOnly);    QTextStream ts( &line );    if (firstline) {	firstline = FALSE;	ncols=0;	QList<ColType> typelist;	typelist.setAutoDelete(TRUE);	do {	    QString typestr;	    ts >> typestr >> ws;	    ColType* t = 0;	    if ( typestr == "num" ) {		t = new ColType(Numeric);	    } else if ( typestr == "label" ) {		t = new ColType(Label);	    }	    if (t) typelist.append(t);	} while (!ts.eof());	coltype = new ColType[ncols];	for (ColType* t = typelist.first(); t; t = typelist.next()) {	    coltype[ncols++] = *t;	}    } else {	int col=0;	Datum *rowdata = new Datum[ncols];	while ( col < ncols && !ts.eof() ) {	    switch (coltype[col]) {	      case Numeric: {		double value;		ts >> value >> ws;		rowdata[col].dbl = value;		break;	      }	      case Label: {		QString* value = new QString;		ts >> *value >> ws;		rowdata[col].str = value;		break;	      }	    }	    col++;	}	data.append(rowdata);    }    line.close();    line.open(IO_WriteOnly|IO_Truncate);}int Grapher::write(QNPStream* /*str*/, int /*offset*/, int len, void* buffer){    // The browser calls this function when data is available on one    // of the streams the plugin has requested.  Since we are only    // processing one stream - the URL in the SRC argument of the EMBED    // tag, we assume the QNPStream is that one.  Also, since we do not    // override QNPInstance::writeReady(), we must accepts ALL the data    // that is sent to this function.    //    char* txt = (char*)buffer;    for (int i=0; i<len; i++) {	char ch = txt[i];	switch ( ch ) {	  case '\n':	    consumeLine();	    break;	  case '\r': // ignore;	    break;	  default:	    line.putch(ch);	}    }    if ( widget() ) {	widget()->update();    }    return len;}void Grapher::aboutPlugin(){    getURL( "http://www.trolltech.com/nsplugin/", "_blank" );}void Grapher::aboutData(){    const char* page = arg("DATAPAGE");    if (page)	getURL( page, "_blank" );    else	QMessageBox::message("Help", "No help for this data");}//// GrapherPlugin is the start of everything.  It is a QNPlugin subclass,// and it is responsible for describing the plugin to the browser, and// creating instances of the plugin when it appears in web page.//class GrapherPlugin : public QNPlugin {public:    GrapherPlugin()    {    }    QNPInstance* newInstance()    {	// Make a new Grapher, our subclass of QNPInstance.	return new Grapher;    }    const char* getMIMEDescription() const    {	// Describe the MIME types which this plugin can	// process.  Just the concocted "application/x-graphable"	// type, with the "g1n" filename extension.	//	return "application/x-graphable:g1n:Graphable ASCII numeric data";    }    const char * getPluginNameString() const    {	// The name of the plugin.  This is the title string used in	// the "About Plugins" page of the browser.	//	return "Qt-based Graph Plugin";    }    const char * getPluginDescriptionString() const    {	// A longer description of the plugin.	//	return "A Qt-based LiveConnected plug-in that graphs numeric data";    }};//// Finally, we provide the implementation of QNPlugin::create(), to// provide our subclass of QNPlugin.//QNPlugin* QNPlugin::create(){    return new GrapherPlugin;}#include "grapher.moc"

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -