- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания QT 4 программирование GUI на С++ Жасмин Бланшет
Шрифт:
Интервал:
Закладка:
189 void Plotter::refreshPixmap()
190 {
191 pixmap = QPixmap(size());
192 pixmap.fill(this, 0, 0);
193 QPainter painter(&pixmap);
194 painter.initFrom(this);
195 drawGrid(&painter);
196 drawCurves(&painter);
197 update();
198 }
Функция refreshPixmap() перерисовывает график на внеэкранной пиксельной карте и обновляет изображение на экране. Мы изменяем размеры пиксельной карты на размеры виджета и заполняем ее цветом стертого виджета. Этот цвет является «темным» компонентом палитры из-за вызова функции setBackgroundRole() в конструкторе Plotter. Если фон задается неоднородной кистью, в функции QPixmap::fill() необходимо указать смещение в виджете, где будет заканчиваться пиксельная карта, чтобы правильно выравнить образец кисти. Здесь пиксельная карта соответствует всему виджету, поэтому мы задаем позицию (0, 0).
Затем мы создаем QPainter для вычерчивания диаграммы на пиксельной карте. Вызов initFrom() устанавливает в рисовальщике перо, фон и шрифт такими же, как для виджета Plotter. Затем мы вызываем функции drawGrid() и drawCurves(), которые рисуют диаграмму. В конце мы вызываем функцию update() для инициации события рисования всего виджета. Пиксельная карта копируется в виджет функцией paintEvent().
199 void Plotter::drawGrid(QPainter *painter)
200 {
201 QRect rect(Margin, Margin,
202 width() - 2 * Margin, height() - 2 * Margin);
203 if (!rect.isValid())
204 return;
205 PlotSettings settings = zoomStack[curZoom];
206 QPen quiteDark = palette().dark().color().light();
207 QPen light = palette().light().color();
208 for (int i = 0; i <= settings.numXTicks; ++i) {
209 int x = rect.left() + (i * (rect.width() - 1)
210 / settings.numXTicks);
211 double label = settings.minX + (i * settings.spanX()
212 / settings.numXTicks);
213 painter->setPen(quiteDark);
214 painter->drawLine(x, rect.top(), x, rect.bottom());
215 painter->setPen(light);
216 painter->drawLine(x, rect.bottom(), x, rect.bottom() + 5);
217 painter->drawText(x - 50, rect.bottom() + 5, 100, 15,
218 Qt::AlignHCenter | Qt::AlignTop,
219 QString::number(label));
220 }
221 for (int j = 0; j <= settings.numVTicks; ++j) {
222 int y = rect.bottom() - (j * (rect.height() - 1)
223 / settings.numYTicks);
224 double label = settings.minY + (j * settings.spanY()
225 / settings.numYTicks);
226 painter->setPen(quiteDark);
227 painter->drawLine(rect.left(), у, rect.right(), у);
228 painter->setPen(light);
229 painter->drawLine(rect.left() - 5, y, rect.left(), у);
230 painter->drawText(rect.left() - Margin, у - 10, Margin - 5, 20,
231 Qt::AlignRight | Qt::AlignVCenter,
232 QString::number(label));
233 }
234 painter->drawRect(rect.adjusted(0, 0, -1, -1));
235 }
Функция drawGrid() чертит сетку под кривыми и осями. Область для вычерчивания сетки задается прямоугольником rect. Если размеры виджета недостаточны для размещения графика, мы сразу возвращаем управление.
Первый цикл for проводит вертикальные линии сетки и отметки по оси x. Второй цикл for выводит горизонтальные линии и отметки по оси y. В конце мы рисуем прямоугольники по окаймляющей кромке. Функция drawText() применяется для вывода числовых значений для отметок обеиз осей.
Вызовы функции drawText() имеют следующий формат:
painter.drawText(x, у, ширина, высота, смещение, текст);
где (x, у, ширина, высота) определяют прямоугольник, смещение задает позицию текста в этом прямоугольнике и текст представляет собой выводимый текст.
236 void Plotter::drawCurves(QPainter *painter)
237 {
238 static const QColor colorForIds[6] = {
239 Qt::red, Qt::green, Qt::blue, Qt::cyan, Qt::magenta, Qt::yellow };
240 PlotSettings settings = zoomStack[curZoom];
241 QRect rect(Margin, Margin,
242 width() - 2 * Margin, height() - 2 * Margin);
243 if (!rect.isValid())
244 return;
245 painter->setClipRect(rect.adjusted(+1, +1, -1, -1));
246 QMapIterator<int, QVector<QPointF> > i(curveMap);
247 while (i.hasNext()) {
248 i.next();
249 int id = i.key();
250 const QVector<QPointF> &data = i.value();
251 QPolygonF polyline(data.count());
252 for (int j = 0; j < data.count(); ++j) {
253 double dx = data[j].x() - settings.minX;
254 double dy = data[j].y() - settings.minY;
255 double x = rect.left() + (dx * (rect.width() - 1)
256 / settings.spanX());
257 double у = rect.bottom() - (dy * (rect.height() - 1)
258 / settings.spanY());
259 polyline[j] = QPointF(x, у);
260 }
261 painter->setPen(colorForIds[uint(id) % 6]);
262 painter->drawPolyline(polyline);
263 }
264 }
Функция drawCurves() рисует кривые поверх сетки. Мы начинаем с вызова функции setClipRect для ограничения области отображения QPainter прямоугольником, содержащим кривые (без окаймляющей кромки и рамки вокруг графика). После этого QPainter будет игнорировать вывод пикселей вне этой области.
Затем мы выполняем цикл по всем кривым, используя итератор в стиле Java, и для каждой кривой мы выполняем цикл по ее точкам QPointF. Функция key() позволяет получить идентификатор кривой, а функция value() — данные соответствующей кривой в виде вектора QVector<QPointF>. Внутри цикла for производятся преобразование всех точек QPointF из системы координат построителя графика в систему координат виджета и сохранение их в переменной polyline.
После преобразования всех точек кривой в систему координат виджета мы устанавливаем цвет пера для кривой (используя один из наборов заранее определенных цветов) и вызываем drawPolyline() для вычерчивания линии, которая проходит по всем точкам кривой.
Этим мы завершаем построение класса Plotter. Остается только рассмотреть несколько функций настроек графика PlotSettings.
265 PlotSettings::PlotSettings()
266 {
267 minX = 0.0;
268 maxX = 10.0;
269 numXTicks = 5;
270 minY = 0.0;
271 maxY = 10.0;
272 numYTicks = 5;
273 }
Конструктор PlotSettings инициализирует обе оси координат диапазоном от 0 до 10 с пятью отметками.
274 void PlotSettings::scroll(int dx, int dy)
275 {
276 double stepX = spanX() / numXTicks;
277 minX += dx * stepX;
278 maxX += dx * stepX;
279 double stepY = spanY() / numYTicks;
280 minY += dy * stepY;
281 maxY += dy *stepY;
282 }
Функция scroll() увеличивает (или уменьшает) minX, maxX, minY и maxY на интервал между двух отметок, помноженный на заданное число. Данная функция применяется для реализации скроллинга в функции Plotter::keyPressEvent().
283 void PlotSettings::adjust()
284 {
285 adjustAxis(minX, maxX, numXTicks);
286 adjustAxis(minY, maxY, numYTicks);
287 }
Функция adjust() вызывается из mouseReleaseEvent() для округления значений minX, maxX, minY и maxY, чтобы получить «удобные» значения, и определения количества меток на каждой оси. Закрытая фyнкция adjustAxis() выполняет эти действия отдельно для каждой оси.
288 void PlotSettings::adjustAxis(double &min, double &max, int &numTiсks)
289 {
290 const int MinTicks = 4;
291 double grossStep = (max - min) / MinTicks;
292 double step = pow(10.0, floor(log10(grossStep)));
293 if (5 * step < grossStep) {
294 step *= 5;
295 } else if (2* step < grossStep) {
296 step *= 2;
297 }
298 numTicks = int (ceil(max / step) - floor(min / step));
299 if (numTicks < MinTicks)
300 numTicks = MinTicks;
301 min = floor(min / step) * step;
302 max = ceil(max / step) * step;
303 }
Функция adjustAxis() преобразует свои параметры min и max в «удобные» числа и устанавливает свой параметр numTicks на количество меток, которое, по ее расчету, подходит для заданного диапазона [min, max]. Поскольку в функции adjustAxis() фактически требуется модифицировать переменные (minX, maxX, numXTicks и так далее), а не просто копировать их, для этих параметров не используется модификатор const. Большая часть программного кода в adjustAxis() предназначена просто для определения соответствующего значения интервала между двумя метками (переменная step — шаг). Для получения на оси удобных чисел мы должнытщательно выбирать этот шаг. Например, значение шага 3.8 привело бы к появлению на оси чисел, кратных 3.8, что затрудняет восприятие диаграммы человеком. Для осей с десятичной системой обозначения «удобными» значениями шага являются числа вида 10n, 2 • 10n или 5 • 10n.