Пример: программа считывает массив неотрицательных чисел из файла, выводит его на экран, используя полосы прокрутки, и рисует круговую диаграмму для 13 самых больших элементов, отображая остальные в сумме.
С оздайте проект на базе главного окна. Добавьте класс Pole, производный от QWidget. В главном окне создадим область прокрутки и поместим в эту область поле, на котором выведем массив и отображающую его круговую диаграмму.
В меню главного окна добавьте меню File и действие Open.
В файл mainwindow.cpp добавьте показанный ниже код.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "pole.h"
MainWindow::MainWindow(QWidget *parent):
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QTextCodec* codec = QTextCodec::codecForName("UTF-8");
QTextCodec::setCodecForCStrings(codec);
QScrollArea* scroll = new QScrollArea(this);
// создаем область прокрутки
Pole* pole = new Pole(scroll); // создаем новый виджет
scroll->setWidget(pole); // размещаем виджет в области прокрутки
setCentralWidget(scroll); // делаем область прокрутки рабочей областью окна
connect(ui->actionOpen, SIGNAL(triggered()), pole, SLOT(fileOpen()));
// связываем вызов команды File|Open со слотом, который мы создадим в классе Pole
|
|
}
MainWindow::~MainWindow()
{
delete ui;
}
В файл pole.h добавьте показанный ниже код.
#ifndef POLE_H
#define POLE_H
#include <QWidget>
#include <QtGui>
class Pole: public QWidget
{
Q_OBJECT
public:
explicit Pole(QScrollArea* parent = 0);
// измените тип указателя на родительское окно
QScrollArea* Parent; // указатель на область прокрутки
void paintEvent(QPaintEvent *); // перерисовывает содержимое окна
QFile file; // файл, содержащий массив
QString fileName; // имя файла
QVector<double> v; // массив
QVector<double> copyV; // копия массива
QFont font; // шрифт
int dy; // расстояние между элементами массива при выводе на экран
int k; // количество элементов массива
void Pie(QPainter&, QRect&, int, int, int);
// рисует один кусок диаграммы
signals:
public slots:
void fileOpen(); // слот, считывающий массив из файла
};
#endif // POLE_H
В файл pole.cpp добавьте показанный ниже код.
#include "pole.h"
#include "mainwindow.h"
Pole::Pole(QScrollArea* parent): // измените тип указателя на родительское окно
QWidget(parent)
{
Parent = parent; // запоминаем значение указателя
}
void Pole::paintEvent(QPaintEvent *) // отображаем массив на экране:
{
QPainter painter(this);
int y = 20; // уровень, с которого начинается вывод массива на экран
painter.setFont(font); // устанавливаем шрифт
// Вывод массива:
double sum = 0; // сумма элементтов массива
k = v.size(); // размер массива
for (int i = 0; i < k; ++i) // проходим по массиву
{
painter.drawText(10, y, QString::number(v[i]));
// выводим очередной элемент массива на экран
y += dy; // переходим на другую строку
sum += v[i]; // добавляем элемент к сумме
}
copyV = v;
// копируем массив, чтобы исходный массив отображался на экране без изменений
qSort(copyV.begin(), copyV.end(), qGreater<double>());
// сортируем копию массива по убыванию, чтобы построить диаграмму
|
|
// Диаграмма:
QRect rectBase = Parent->rect();
// прямоугольник, соответствующий видимой части области прокрутки
QRect rect = rectBase; // прямоугольник, в котором мы будем рисовать диаграмму
int h = rectBase.height()-25; // несколько уменьшим высоту прямоугольника
rect.setSize(QSize(h,h)); // задаем квадрат высотой h
rect.moveRight(rectBase.width()-25); // перемещаем квадрат к правой границе окна
double startAngle = 0; // начальный угол для первого фрагмента диаграммы
double spanAngle = 0; // угол,
for (int i = 0; i < qMin(13, k); ++i) //
{
spanAngle = 360 * 16.* copyV[i] / sum; // Угол между радиусами
Pie(painter, rect, startAngle, spanAngle, i);
// рисуем сектор с помощью функции, определенной ниже
startAngle += spanAngle; // переходим к следующему сектору
}
if (k > 13) // отображаем остальные элементы массива в сумме:
{
spanAngle = 360*16 - startAngle; // определяем размер соответствующего угла
Pie(painter, rect, startAngle, spanAngle, 13);
// рисуем оставшуюся часть диаграммы
}
}
void Pole::fileOpen()
{
if (file.isOpen()) file.close();
v.clear(); // удаляем ранее считанный массив
copyV.clear(); // и его копию
fileName = QFileDialog::getOpenFileName(this, "Открыть файл", QString(),
QString("Текстовые файлы (*.txt);;Все файлы (*.*)"));
// считываем имя файла с помощью специального окна
if (!fileName.isEmpty()) // если имя файла выбрано
{
file.setFileName(fileName);
// связываем объект файл с физическим файлом на диске
file.open(QIODevice::ReadOnly); // открываем файл
QTextStream in(&file); // создаем поток для работы с файлами
double x; // одно число из файла
while (true) // как бы бесконечный цикл для чтения данных из файла
{
in >> x; // считываем одно число
if (x < 0) // если число недопустимо
{
QMessageBox::critical(this, "Ошибка в данных",
"Все числа должны быть больше 0");
return;
}
if (!in.atEnd()) // если файл не закончен
v << x; // записываем число
else break; //
}
font = QFont("Serif", 12); //
QFontMetrics fm(font); //
dy = fm.height(); //
k = v.size(); //
int height = qMax(1500, 20 + k*dy); //
this->resize(1500, height); //
}
}
void Pole::Pie(QPainter & painter,QRect& rect, int startAngle, int spanAngle, int i)
{ //
int c = i+1; //
int I, R,G,B; //
B = c % 2; c /= 2; //
G = c % 2; c /= 2; //
R = c % 2; c /= 2; //
I = c % 2; //
painter.setBrush(QBrush(QColor(I*100+R*155,I*100+G*155,I*100+B*155))); //
painter.drawPie(rect, startAngle, spanAngle); //
}