QT: создание гистограммы на безголовом сервере AMI. Не удается запустить X Display

#qt #amazon-ec2

#qt #amazon-ec2

Вопрос:

Я выполняю некоторую обработку на сервере Amazon Linux EC2 AWS. Когда что-то идет не так, мне нужно отправить электронное письмо с гистограммой. Я хочу сам сгенерировать гистограмму, и я делаю это с помощью QPainter и QImage. Прямо сейчас я разрабатываю пример приложения для простого создания гистограммы. Итак, что я делаю, так это разрабатываю на своем ноутбуке, и когда у меня есть что-то, что работает, загружаю код на сервер EC2 и компилирую его там. Затем запустите полученное приложение на сервере.

Однако вот в чем проблема. Когда я попытался нарисовать текст с помощью QPainter, программа на моем ноутбуке вышла из строя. Это связано с тем, что я использую QCoreApplication вместо QApplication в моем main.cpp .

Поэтому я перехожу на QApplication, который устраняет проблему. Я загружаю код на сервер и компилирую его. Затем, когда я пытаюсь запустить его, я получаю:

 qt.qpa.screen: QXcbConnection: Could not connect to display 
Could not connect to any X display.
 

Это, конечно, потому, что сервер безголовый.
Мой вопрос таков: есть ли что-то, что я могу установить на сервере, что позволило бы мне в полной мере использовать возможности QPainter?

Редактировать:

Мой main.cpp

 #include <QApplication>
#include "../../CommonClasses/DataAnalysis/BarGrapher/bargrapher.h"

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

    // Setup
    qreal W = 1024;
    qreal H = 768;

    // A fictional data set;
    QList<qreal> ds1;
    ds1 << 50 << 500 << 368 << 198;

    QStringList descs;
    descs << "Item 1";
    descs << "A somewhat long and complex description";
    descs << "Item 2";
    descs << "Item Another";

    // The actual bar graph
    BarGrapher bg;
    bg.configureGraphText(W,H,descs,"Some sort of label","The title of this damn thing");
    BarGrapher::DataSet ds;
    ds << ds1;
    QImage result = bg.generateGraph(ds);

    qWarning() << "ERROR" << bg.getError();

    result.save("mytest.png");
    qWarning() << "DONE";

    return a.exec();
}
 

Мой bargrapher.cpp

 #include "bargrapher.h"

const qreal BarGrapher::PROYECTION_FACTOR = 0.707106;
const qreal BarGrapher::LEFT_MARGIN  = 0.1;
const qreal BarGrapher::RIGHT_MARGIN = 0.04;
const qreal BarGrapher::TOP_MARGIN   = 0.08;

BarGrapher::BarGrapher()
{

}


void BarGrapher::configureGraphText(qreal width, qreal height, const QStringList amp;xItems, const QString amp;ylabel, const QString amp;title){
    graphTitle = title;
    W = width;
    H = height;
    itemDescriptions = xItems;
    yAxisText = ylabel;
}


QImage BarGrapher::generateGraph(const DataSet amp;dataSet){

    QImage graph(W,H,QImage::Format_RGB888);
    error = "";

    // Making sure that the data is coherent.
    if (dataSet.isEmpty()){
        error = "No data was presented";
        return graph;
    }
    if (dataSet.size() > 2){
        error = "Cannot have more than two data sets, passed "   QString::number(dataSet.size());
        return graph;
    }

    qint32 numItems = dataSet.first().size();
    for (qint32 i = 0; i < dataSet.size(); i  ){
        if (numItems != dataSet.at(i).size()){
            error = "All data sets must be the same size: "   QString::number(numItems)   " however data set "   QString::number(i)   " has "   QString::number(dataSet.at(i).size());
            return graph;
        }
    }

    if (!itemDescriptions.isEmpty()){
        if (numItems != itemDescriptions.size()){
            error = "The number of item descriptios ("   QString::number(itemDescriptions.size())   ") must coincide with the numer of points in the data set ("   QString::number(numItems)   ")";
            return graph;
        }
    }
    else{
        for (qint32 i = 0; i < numItems; i  ){
            itemDescriptions << QString::number(i);
        }
    }

    // The font to be used
    QFont textFont("Mono");
    textFont.setPixelSize(10);
    //QFont titleFont("Mono",16,QFont::Bold);

    // Calculating margins to get the effective graph area.
    qreal XAxisLength = (1.0 - LEFT_MARGIN - RIGHT_MARGIN)*W;
    qreal DW = XAxisLength/(qreal)(numItems);

    // Calculating the effective graph area due to the text items.
    qreal Th = 0.1*H;
    qreal GH = (1.0-TOP_MARGIN)*H - Th;
    qreal xOffset = LEFT_MARGIN*W;
    qreal yOffset = TOP_MARGIN*H;

    // --------------- Commence drawing -----------------------
    QPainter painter(amp;graph);

    // The background
    painter.setBrush(QBrush(QColor(226,226,226)));
    painter.drawRect(0,0,W,H);

    // Drawing the axis;
    QPen pen;
    pen.setColor(QColor(0,0,0));
    pen.setWidth(2);
    painter.setPen(pen);
    painter.setBrush(QBrush(Qt::black));

    painter.drawLine(xOffset,yOffset GH,xOffset   XAxisLength,yOffset GH);
    painter.drawLine(xOffset,yOffset,xOffset,yOffset GH);

    // Drawing the X Axis text
    painter.setFont(textFont);
    for (qint32 i = 0; i < numItems; i  ){
        QRectF rectF(xOffset   i*DW,yOffset GH,DW,Th);
        painter.drawText(rectF,itemDescriptions.at(i));
    }

    return graph;
}
 

Комментарии:

1. Пожалуйста, покажите свой код. Ошибки, которые вы видите, — это то, что я мог бы ожидать, если бы вы пытались использовать a QPixmap , а не a QImage .

2. Добавлен полный код. Но я не использую QPixmap. И проблема, на мой взгляд, связана с тем фактом, что для рисования текста требуется «подключение» (не знаю, как это описать) к оконной системе, которой нет на сервере Amazon

3. Извините, я немного неправильно истолковал вопрос. Можете ли вы объяснить, что происходит, когда вы используете QCoreApplication вместо QApplication — это, кажется, работает нормально для меня.

4. Я делаю? Моя программа завершает работу с painter.DrawText (RectF,itemDescriptions.at (i));

5. попробуйте использовать QGuiApplication вместо QApplication.