1.需求分析
分为两个部分:时间显示和时区显示修改。时间显示包括日期显示和当前时分秒显示。日期在日历中展示出来,当前时分秒使用三个spinner。时区通过地图显示,通过地图上方的下拉列表框修改。点击“Apply”和”Cancel”的时候分别更改/不更改内容;点击”OK”时显示更改后的内容并退出程序。
2.概要设计
九种数据:
- 秒钟设置(0-59)
- 分钟设置(0-59)
- 小时设置(24小时制,0-23)
- 当前日
- 当前月份
- 当前年份
- 当前选择的时区时间
- 当前时区相对标准时间的偏差
- 当前选择的时区的标题
3.详细设计
日历:通过Qt的日历组件实现。
时间:通过三个spinbox实现。改变和改变的关联通过槽函数实现。
两个不同界面:通过tabWidget组件实现。
时区:通过Combo box显示。
时钟:通过QPaintEvent()函数实现,分别画时针、分针、秒针。
地图的显示:通过在图片上增加一个透明度为120
时区的改变:当点击Apply按钮时,将框移动到当前时区对应的地图位置(和箭头相同);当点击Cancel时,将下拉列表框的内容恢复为改变之前的内容(通过一个变量保存),将绿色箭头恢复到原来位置。点击OK按钮时,退出程序。
4.调试分析
在写弹出窗口的时候出现了这样的错误:
百度发现这个问题很少,在stackoverflow上看到一个人在使用印度语的时候出现了这个问题;后来看到有人说Qt的bug report里有这个问题:[OpenType-Rendering-Issue] (https://bugreports.qt.io/browse/QTBUG-30213),在转换时会无法输出文字信息,而是显示方块(下图):不能解决。问了同学,也没有实现这个实验要求。所以我就选择不显示messageBox,在OK和apply的时候只执行更改确认的操作。
5.用户使用说明
通过spinbox改变当前时间;通过下拉列表框选中需要改到的时区,会在下面用箭头提示地图上的位置。点击”OK”或”Apply”可以改变当前时区,点击”Cancel”会取消改变并将箭头和下拉列表框的内容恢复之前的内容。
6.测试结果
直接运行:显示当前北京时间,时区默认为(GMT+8:00)。
对时区的改变:
在下拉列表框中选择想要的内容:(此处选择GMT-11:00)
点击选中:
点击“Cancel“:
点击”Apply”:
对时间的改变:
当前时间:
改变分钟的spinbox:(减小):
增加到临界点:
继续增加:
7.附录
Time_adjust.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
RESOURCES += \
timezone_map_small.qrc
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include<QTimer>
#include<QPainter>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
bool eventFilter(QObject *obj, QEvent *event);
void paintEvent(QPaintEvent* );
public slots:
void do_second();
private slots:
void on_OKButton_clicked();
void on_secondSpinBox_valueChanged(int arg1);
void on_minuteSpinBox_valueChanged(int arg1);
void on_hourSpinBox_valueChanged(int arg1);
void on_cancelButton_clicked();
void on_applyButton_clicked();
void on_comboBox_currentIndexChanged(int index);
private:
Ui::MainWindow *ui;
QTimer* timer1s;
int currentTimeZoneIndex;
};
#endif // MAINWINDOW_H
mainwindow.h
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QMessageBox>
#include<QLabel>
#include<QMovie>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//显示地图图片
QMovie *movie = new QMovie("D:/code/Qt/time_adjust/timezone_map_small.gif");
ui->mapSetTimeLabel->setMovie(movie);
movie->setScaledSize(ui->mapSetTimeLabel->size());
movie->start();
//显示当前北京时间
ui->comboBox->setCurrentIndex(20);
ui->arrowLabel->move(480, 320);
ui->frameorkLabel->move(480, 90);
//获取当前时间
QDateTime current_date_time = QDateTime::currentDateTime();
QTime current_time = current_date_time.time();
int hour = current_time.hour();
int minute = current_time.minute();
int second = current_time.second();
//保存当前时间
currentTimeZoneIndex = 20;
//将当前时间显示在spinbox中
ui->hourSpinBox->setValue(hour);
ui->minuteSpinBox->setValue(minute);
ui->secondSpinBox->setValue(second);
setWindowTitle("time showing");
setWindowIconText("Good");
// ui->hourSpinBox->setAttribute(Qt::WA_Hover,true);//开启悬停事件
// ui->hourSpinBox->installEventFilter(this); //安装事件过滤器
// ui->minuteSpinBox->setAttribute(Qt::WA_Hover,true);
// ui->minuteSpinBox->installEventFilter(this);
// ui->secondSpinBox->setAttribute(Qt::WA_Hover,true);
// ui->secondSpinBox->installEventFilter(this);
//设置计时器每秒钟秒数+1
timer1s = new QTimer();
timer1s->setInterval(1000);
timer1s->start();
//连接信号与槽
connect(timer1s, SIGNAL(timeout()), this, SLOT(do_second()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::do_second(){
int value = ui->secondSpinBox->value();
value++;
ui->secondSpinBox->setValue(value);
//repaint
repaint();
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
//事件过滤器
if(obj == ui->hourSpinBox||obj == ui->minuteSpinBox||obj == ui->secondSpinBox) {
if(event->type() == QEvent::HoverEnter) {
timer1s->stop();
return true;
}else if(obj == ui->hourSpinBox){
if(event->type() == QEvent::HoverLeave){
timer1s->start();
return true;
}
}
}
return QWidget::eventFilter(obj,event);
}
void MainWindow::on_OKButton_clicked()
{
int adjustment = ui->comboBox->currentIndex()-20;//设置相对于北京时间的更改
int x = 120 + ui->comboBox->currentIndex()*18;
ui->arrowLabel->move(x, 320);
ui->frameorkLabel->move(x, 90);
//change timezone show
QString data = ui->comboBox->currentText();
ui->timezoneLabel->setText("Current Time Zone:"+data);
currentTimeZoneIndex = ui->comboBox->currentIndex();
//change time show
QDateTime current_date_time = QDateTime::currentDateTime();
QTime current_time = current_date_time.time();
int hour = current_time.hour();
int minute = current_time.minute();
int second = current_time.second();
hour += adjustment;
//将改变后的时间显示在spinbox中
ui->hourSpinBox->setValue(hour);
ui->minuteSpinBox->setValue(minute);
ui->secondSpinBox->setValue(second);
this->close();
}
void MainWindow::on_secondSpinBox_valueChanged(int arg1)
{
if(arg1==-1){
//减少到-1
//改变分钟:原来数值-1
int min = ui->minuteSpinBox->value();
min--;
ui->minuteSpinBox->setValue(min);
//改变秒钟:59
ui->secondSpinBox->setValue(59);
}else if(arg1==60){
//增加到60
//改变分钟:原来数值+1
int min = ui->minuteSpinBox->value();
min++;
ui->minuteSpinBox->setValue(min);
//改变秒钟:0
ui->secondSpinBox->setValue(0);
}
//repaint
repaint();
}
void MainWindow::on_minuteSpinBox_valueChanged(int arg1)
{
if(arg1==-1){
//减少到-1
//改变时钟:原来数值-1
int hour = ui->hourSpinBox->value();
hour--;
ui->hourSpinBox->setValue(hour);
//改变分钟:59
ui->minuteSpinBox->setValue(59);
}else if(arg1==60){
//增加到60
//改变时钟:原来数值+1
int hour = ui->hourSpinBox->value();
hour++;
ui->hourSpinBox->setValue(hour);
//改变分钟:0
ui->minuteSpinBox->setValue(0);
}
//repaint
repaint();
return;
}
void MainWindow::on_hourSpinBox_valueChanged(int arg1)
{
if(arg1==-1){
ui->hourSpinBox->setValue(23);
}else if(arg1==24){
ui->hourSpinBox->setValue(0);
}
//repaint
repaint();
}
void MainWindow::on_cancelButton_clicked()
{
QDateTime current_date_time = QDateTime::currentDateTime();
QTime current_time = current_date_time.time();
int hour = current_time.hour();
int minute = current_time.minute();
int second = current_time.second();
//将改变后的时间显示在spinbox中
ui->hourSpinBox->setValue(hour);
ui->minuteSpinBox->setValue(minute);
ui->secondSpinBox->setValue(second);
//将comboxBox的内容和绿色箭头恢复
ui->comboBox->setCurrentIndex(currentTimeZoneIndex);
int x = 120 + currentTimeZoneIndex*18;
ui->arrowLabel->move(x, 320);
// //弹出提示框
// QMessageBox* msg = new QMessageBox(this);
// msg->setWindowTitle("Date_and_time");
// msg->setText("Cancelled...\n=========="
// "\nYear = "+QString(year)+
// "\nMonth = "+QString(current_date.month())+
// "\nDay = "+QString(current_date.day())+
// "\nHour = "+QString(hour)+
// "\nMinute = "+QString(minute)+
// "\nSecond = "+QString(second)+
// "\nTimezone = "+QString(currentTimeZone)+
// "\nAuto Daylight = false"+
// "\n=========="+
// "\n(Time not saved)"
// );
// msg->show();
}
void MainWindow::on_applyButton_clicked()
{
int adjustment = ui->comboBox->currentIndex()-20;//设置相对于北京时间的更改
//change timezone show
QString data = ui->comboBox->currentText();
ui->timezoneLabel->setText("Current Time Zone:"+data);
int x = 120 + ui->comboBox->currentIndex()*18;
ui->arrowLabel->move(x, 320);
ui->frameorkLabel->move(x, 90);
currentTimeZoneIndex = ui->comboBox->currentIndex();
//change time show
QDateTime current_date_time = QDateTime::currentDateTime();
QTime current_time = current_date_time.time();
int hour = current_time.hour();
int minute = current_time.minute();
int second = current_time.second();
hour += adjustment;
//将改变后的时间显示在spinbox中
ui->hourSpinBox->setValue(hour);
ui->minuteSpinBox->setValue(minute);
ui->secondSpinBox->setValue(second);
}
void MainWindow::paintEvent(QPaintEvent *)
{
static const QPoint hour[3] = {
QPoint(14, 15),
QPoint(-14, 15),
QPoint(0, -110)
};
static const QPoint minute[3] = {
QPoint(11, 13),
QPoint(-11, 13),
QPoint(0, -170)
};
static const QPoint second[3] = {
QPoint(7, 8),
QPoint(-7, 8),
QPoint(0, -210)
};
int size=qMin(width(),height());
// QTime time=QTime::currentTime();//获取系统当前时间
int current_hour = ui->hourSpinBox->text().toInt();
int current_minute = ui->minuteSpinBox->text().toInt();
int current_second = ui->secondSpinBox->text().toInt();
QPainter p(this);//创建画家对象
p.setRenderHint(QPainter::Antialiasing);//防止图形走样
p.translate(width()/1.25,height()/2);//平移坐标系置中心
p.scale(size/920.0,size/920.0);//缩放
QBrush brush;//定义画刷
brush.setColor(QColor(245,182,96));//设置画刷颜色
brush.setStyle(Qt::SolidPattern);//设置样式
QPen pen;//定义画笔
pen.setWidth(18);//设置画笔宽度
pen.setColor(QColor(205,214,216));//rgb设置颜色
pen.setStyle(Qt::SolidLine);//设置风格
p.setPen(pen);//将画笔交给画家
p.drawEllipse(QPoint(0,0),280,280);//画圆
pen.setColor(Qt::white);
pen.setWidth(160);//设置画笔宽度
p.setPen(pen);//将画笔交给画家
p.drawEllipse(QPoint(0,0),160,160);//画圆
//画时针
p.setBrush(brush);//将画刷交给画家
p.setPen(Qt::NoPen);
p.save();//保存当下状态
p.rotate(30.0*(current_hour+current_minute/60.0));//图形旋转,以原点为旋转中心,顺时针水平旋转对应时针的角度
p.drawConvexPolygon(hour,3);//画时针这个凸多边形,第一个参数为所有的点,第二个参数为点的个数
p.restore();//恢复上一次保存的结果,和save()成对出现
//绘制小时线
pen.setStyle(Qt::SolidLine);
pen.setWidth(5);
pen.setColor(Qt::black);
p.setPen(pen);
for(int i=0;i<12;i++)
{
p.drawLine(0,268,0,276);//画小时线
p.drawText(-5,-235,QString::number(i));//表明小时数
p.rotate(30);//每画一次旋转30度
}
//画分针
p.setPen(Qt::NoPen);
p.setBrush(QColor(144,199,247));
p.save();//保存当下状态
p.rotate(6.0*(current_minute+current_second/60.0));//顺时针旋转至分针的位置
p.drawConvexPolygon(minute,3);//画分针这个凸多边形,第一个参数为所有的点,第二个参数为点的个数
p.restore();//恢复上一次保存的结果,和save()成对出现
//绘制分钟线
pen.setStyle(Qt::SolidLine);
pen.setColor(QColor(0,0,0));
pen.setWidth(1);
p.setPen(pen);
for(int i=0;i<60;i++)
{
if((i%5)!=0)
p.drawLine(0,265,0,276);//5的倍数时不画,因为有小时线
p.rotate(6);//每画一次旋转6度
}
//画秒线
p.setPen(Qt::NoPen);
p.setBrush(QColor(119,217,175));
p.save();
p.rotate(6*current_second);//顺时针旋转至秒针的位置
p.drawConvexPolygon(second, 3);//画秒针这个凸多边形,第一个参数为所有的点,第二个参数为点的个数
p.restore();
//画圆心
p.setBrush(Qt::black);
p.setPen(Qt::white);
p.save();
p.drawEllipse(QPoint(0,0),3,3);//画圆心
p.restore();
//表明上午还是下午
p.setPen(Qt::black);
if(current_hour>=12)
p.drawText(-6,-50,"PM");//画文本区
else
p.drawText(-6,-50,"AM");//画文本区
}
void MainWindow::on_comboBox_currentIndexChanged(int index)
{
int x = 120 + index*18;
ui->arrowLabel->move(x, 320);
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}