LINUX.ORG.RU

[Qt][QPainter] Не могу нарисовать диаграмму.

 


0

2

Привет, ЛОР.

Есть одна простая и понятная насквозь программа. А у нее есть фатальный недостаток - она не работает. А у меня совершенно нет идей, почему.

 QLabel* diagramm(const QPainter::CompositionMode& mode)
    {
        QLabel* plbl = new QLabel;
        plbl->setFixedSize(100, 100);

        QRect    rect(plbl->contentsRect());
        QPainter painter;
        
        int marks[5] = {15,72,73,72,170};//массив людей с оценками
        int peopleCount = 0; //число людей
        int *pmark = marks;
        for(int i = 0; i< sizeof(marks)/sizeof(int); i++, pmark++) { peopleCount+=*pmark; }
        double gradMultiplier = 360/peopleCount; //множитель для преобразования люди-> градусы

        for(int i = 0; i< sizeof(marks)/sizeof(int); i++, pmark++) { *pmark = static_cast<int>(*pmark * gradMultiplier); }

       QImage resultImage(rect.size(), QImage::Format_ARGB32_Premultiplied);//сюда будем рисовать
        double grad = 0; //уже нарисованные градусы

        //очищаем изображение
        painter.begin(&resultImage);
        painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
        painter.eraseRect(rect);
        painter.drawImage(rect, resultImage);
        painter.end();

     //рисуем диаграмму
     for(int mark = 0; mark< (sizeof(marks)/sizeof(int)); mark++){
        painter.begin(&resultImage);
        painter.setCompositionMode(QPainter::CompositionMode_Darken);
        painter.setPen(QPen(QColor(mark*25, mark*25, mark*25), 1));
        painter.setBrush(QBrush(QColor(mark*25, mark*25, mark*25)));
        painter.drawPie(rect, grad, marks[mark]*16);
        grad+=marks[mark]*16;
        painter.setCompositionMode(mode);
        painter.drawImage(rect, resultImage);
        painter.end();
     }
        plbl->setPixmap(QPixmap::fromImage(resultImage));

     return plbl;
    }


    int main(int argc, char** argv)
    {
       QApplication app(argc, argv);
       QWidget      wgt;

       
       QGridLayout* pgrd = new QGridLayout;
       pgrd->addWidget(diagramm(QPainter::CompositionMode_SourceOver), 0, 0);
       pgrd->addWidget(new QLabel("<CENTER>Diagramm</CENTER>"), 1, 0);
       wgt.setLayout(pgrd);

       wgt.show();

       return app.exec();
    }

Программа должна строить диаграмму по кол-ву людей с определенными оценками. Пока все прописано прямо в коде, потом усложню, не суть. Собсно вроде все прозрачно и понятно, но не хочет рисовать диаграмму правильно, т.е. gradMultiplier как бы не учитывается и рисуется столько градусов, сколько человек(причем если peopleCount >360, вместо диаграммы получаем ничего).

Помогите пожалста, а то я даже придумать не могу ничего.

★★

for(int i = 0; i< sizeof(marks)/sizeof(int); i++, pmark++) { peopleCount+=*pmark; }

После этого цикла pmark указывает на область памяти после массива marks.

for(int i = 0; i< sizeof(marks)/sizeof(int); i++, pmark++) { *pmark = static_cast<int>(*pmark * gradMultiplier); }

В этом цикле начальное значение pmark указывает чёрти куда. Почему программа не сегфолтится? Ты же затираешь содержимое стека под массивом!

И вообще, никто так циклы не пишет. Либо делается так (вообще без указателей):

int msize = sizeof(marks)/sizeof(marks[0]); // Это можно бы и по-человечески написать
for (int *pmark = marks; pmark < marks+msize; pmark++) {
        *pmark = something();
}

static_cast<int>(*pmark * gradMultiplier);

Убивать.

Либо с указателями:

int msize = sizeof(marks)/sizeof(marks[0]); // Это можно бы и по-человечески написать
for (int i=0; i<msize; i++) {
        marks[i] = something();
}

gentoo_root ★★★★★
()
Ответ на: комментарий от gentoo_root

Хм, чего это парсер ЛОРа переставил местами 3 куска моего сообщения? Блоки кода внизу должны наоборот быть.

gentoo_root ★★★★★
()
Ответ на: комментарий от gentoo_root

Да-да, я уже понял, что сморозил чушь. Больше думать надо, прежде чем писать :)

unC0Rr ★★★★★
()
Ответ на: комментарий от gentoo_root

это я из справочника нахватался и решил попробовать, спасибо, так действительно лучше читается. Но работать он так и не начал, загадка века блин.

Что не так со static_cast, кроме указателя?

S-Mage ★★
() автор топика
Ответ на: комментарий от S-Mage

Что не так со static_cast, кроме указателя?

Как бы можно просто «(int) (выражение)» написать.

double gradMultiplier = 360/peopleCount;

И здесь 360 делится на peopleCount нацело, потому что оба числа целые. Дробная часть отбрасывается, и толку с того, что gradMultiplier вещественный, нет, потому что в него записывается целое число. Надо бы написать вместо «360» «360.0» или «360.».

Других ошибок пока что не вижу, выложи тот код, который получился пока что после этих изменений.

gentoo_root ★★★★★
()

Проведи исследование на тему, чему равно 5/2 в С/C++

P.S. Твою проблему решит такой патч:
--double gradMultiplier = 360/peopleCount;
++double gradMultiplier = 360.0/peopleCount;

trex6 ★★★★★
()
Ответ на: комментарий от gentoo_root

И здесь 360 делится на peopleCount нацело, потому что оба числа целые.

Ну да, логично, потому что 15+72+73+72+170=402, и 360/402<1 => при вычислении 360/402 получится целый 0, и переменной gradMultiplier присвоится 0, поэтому ничего не работает.

gentoo_root ★★★★★
()
Ответ на: комментарий от gentoo_root

bingo! Как-то я забыл, что результат сперва вычислится, потом приведется. Спасибо тебе.

S-Mage ★★
() автор топика
Ответ на: комментарий от gentoo_root

у меня опять проблемы. На сей раз походу с наследованием и я опять не понимаю, что не так. Гугл меня не спас(пишут «запусти qmake и реализуй конструктор/деструктор»). Код:

class diagram : public QLabel
{
    Q_OBJECT

public:
    diagram();
    virtual ~diagram();
public slots:
   void drawDia(QLineEdit *pmarks[]);
   diagram *drawImage(const QPainter::CompositionMode& mode, int marks[marksCount]);

};


// ----------------------------------------------------------------------
diagram::diagram()
{
}

diagram::~diagram()
{
}

Вывод при сборке:

/home/s/qtworkspace/pr1-build-desktop-Qt___PATH________/../pr1/main.cpp:29: undefined reference to `vtable for diagram'
/home/s/qtworkspace/pr1-build-desktop-Qt___PATH________/../pr1/main.cpp:29: undefined reference to `vtable for diagram'
main.o: In function `~diagram':
/home/s/qtworkspace/pr1-build-desktop-Qt___PATH________/../pr1/main.cpp:34: undefined reference to `vtable for diagram'
/home/s/qtworkspace/pr1-build-desktop-Qt___PATH________/../pr1/main.cpp:34: undefined reference to `vtable for diagram'
collect2: ld returned 1 exit status
make: *** [pr1] Error 1

Я ведь правильно понимаю, что мне не надо ничего делать в конструкторе? Я унаследовал класс единственно с целью сделать слот.

S-Mage ★★
() автор топика
Ответ на: комментарий от S-Mage

цитата с rsdn.ru:

Такое часто встречается вот в каком случае:

— создаешь хедер и срр, пишешь класс — добавляешь в проект — прогоняешь qmake — потом добавляешь в класс слоты/сигналы

В этом случае при запуске qmake'а в п.3 не создаются вызовы moc'а, т.к. не было нужно. После добавления сигналов/слотов нужны вызовы moc'а для генерации стабов. Вот их и не хватает для vtable'а. Простой повторный запуск qmake'а не спасает, надо удалить файлы object_script.XXX.debug и object_script.XXX.release.

Вопрос: где эти штуки искать?

S-Mage ★★
() автор топика
Ответ на: комментарий от S-Mage

Если это всё в одном файле, то moc работать не будет — надо объявление класса поместить в заголовочный файл *.h, а реализацию в *.cpp, откуда заинклюдить заголовок.

gentoo_root ★★★★★
()
Ответ на: комментарий от gentoo_root

спасибо. Теперь он мне утверждает, что у меня нет такого слота, хотя он, ясное дело, есть.

Запускается /home/s/qtworkspace/pr1-build-desktop-Qt___PATH________/pr1...
Object::connect: No such slot diagram::drawDia(pmarks) in ../pr1/main.cpp:45
/home/s/qtworkspace/pr1-build-desktop-Qt___PATH________/pr1 завершился с кодом 0
S-Mage ★★
() автор топика
Ответ на: комментарий от S-Mage

Теперь он мне утверждает, что у меня нет такого слота, хотя он, ясное дело, есть.

No such slot diagram::drawDia(pmarks)

И правильно утверждает. Потому что слота «diagram::drawDia(pmarks)» действительно нет. Судя по этому объявлению:

void drawDia(QLineEdit *pmarks[]);

слот называется «diagram::drawDia(QLineEdit **)». Поэтому в функции connect надо писать «SIGNAL(drawDia(QLineEdit **))», а не что-либо иное.

gentoo_root ★★★★★
()
Ответ на: комментарий от gentoo_root

pmarks - массив указателей на QLineEdit же, это вроде то же самое, что указатель на указатель. Что не так?

S-Mage ★★
() автор топика
Ответ на: комментарий от S-Mage

Какой пошлёшь при emit сигнала, такой и будет. Почитай примеры-то хотя бы, чтобы не задавать такие вопросы.

unC0Rr ★★★★★
()
Ответ на: комментарий от unC0Rr

я читал. но сейчас ни фига не понял. Я должен передавать параметры для слота внутри сигнала?

S-Mage ★★
() автор топика
Ответ на: комментарий от unC0Rr

перечитываем про сигналы и слоты:

При создании соединения необходимо помнить о том, что параметры сигнала и слота должны задаваться в одинаковом порядке и иметь одинаковый тип. У сигнала может быть больше параметров, чем у слота, но обратное неверно.

Вот в чем дело, сигнал должен передавать все необходимые параметры.

S-Mage ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.