当前位置: 首页 > news >正文

微信人生里面微网站怎么做手表网站哪个最好知乎

微信人生里面微网站怎么做,手表网站哪个最好知乎,网站制作沈阳,wordpress如何建立网站目录 概述 事件 鼠标事件 进入、离开事件 按下事件 释放事件 双击事件 移动事件 滚轮事件 按键事件 单个按键 组合按键 定时器 QTimerEvent QTimer 窗口事件 文件 输入输出设备 文件读写类 文件和目录信息类 多线程 常用API 线程安全 互斥锁 条件变量…目录 概述 事件 鼠标事件 进入、离开事件 按下事件 释放事件 双击事件 移动事件 滚轮事件 按键事件 单个按键 组合按键 定时器 QTimerEvent QTimer 窗口事件 文件 输入输出设备 文件读写类 文件和目录信息类 多线程 常用API 线程安全 互斥锁 条件变量 信号量 网络 UDP Socket TCP Socket HTTP Client Qt 音视频 Qt 音频 Qt 视频 概述 Qt 是一个跨平台的C开发框架我们要知道的是 Qt 中许多的功能都是操作系统提供的Qt 封装了系统调用那么这一篇就来看一看系统为我们支持了什么吧。 事件 在上上篇中介绍的信号和槽中用户进行的操作可能会产生某种信号给一个信号连接上槽函数当信号触发的时候就可以执行对应的槽函数进而完成各种功能。         除了信号用户进行的操作也会产生事件我们也可以给事件关联上处理函数当事件触发的时候就可以执行对应的代码。         这么一看事件和信号还是差不多的事件本身是操作系统提供的机制Qt 把操作系统的事件机制进行封装但是事件的代码编写起来不是很方便所以 Qt 对于事件进一步封装这就是信号和槽事件就是它的底层机制。         实际 Qt 开发过程中多数的交互功能都是通过信号和槽来完成的但是也有特殊的情况信号和槽无法实现就比如 Qt 中没有这个信号这就需要重写事件处理函数来手动处理事件的逻辑。 所有的 Qt 事件均继承了抽象类 QEvent。当用户进行一些操作就会触发事件常见的 Qt 事件如下 事件名称描述鼠标事件鼠标左键右键滚轮移动按下和松开键盘事件按键类型按键按下按键松开定时器事件定时到达进入、离开事件鼠标的进入和离开滚轮事件鼠标滚轮滚动绘屏事件重绘屏幕的某些部件显示隐藏事件窗口的显示和隐藏移动事件窗口位置的变化窗口事件是否为当前窗口大小改变事件窗口大小改变焦点事件键盘焦点移动拖拽事件用鼠标进行拖拽 鼠标事件 进入、离开事件 之前信号和槽是通过connect来关联的对于事件的处理方式为让当前的类重写某个事件的处理函数使用的是多态的机制子类重写父类的事件处理函数事件触发过程中就可以子类调用子类父类调用父类。         为了理解一下这个事件就写一个简单的程序创建一个按钮当鼠标进入和离开这个控件就会触发事件。处理事件要再创建一个类这个类中重写对应的事件处理函数。类创建好之后给构造函数中添加一个父元素参数这个类已经继承了QPushButton重写两个事件函数就可以了。         之后就可以在图形化界面中拖拽一个QPushButton但是还有一个问题就是这个控件不是我们自己创建的PushButton只有PushButton才可以触发我们自己写的这个事件处理函数。         这里就需要使用这个功能输入要提升的类名称头文件会自己填充一定要注意不要拼错。         之后这里的类名就变成了我们定义的PushButton。         现在就是万事俱备只欠运行了。运行后就会看到进出都会触发对应的处理函数。         所以之前的哪那个表白程序还可以让按钮跑的更快。 void PushButton::enterEvent(QEvent *event) {(void) event; // 这个参数暂时用不到qDebug() enterEvent;QRect rect this-geometry();qDebug() rect;this-setGeometry(rand() % (800 - rect.width()), rand() % (600 - rect.height()), rect.width(), rect.height()); } 按下事件 鼠标按下事件是通过虚函数mousePressEvent来捕获的通过鼠标点击我们也可以获取鼠标点击的位置。 void PushButton::mousePressEvent(QMouseEvent *event) {// 以PushButton左上角为原点qDebug() event-x() : event-y(); // 包含QMouseEvent头文件// 以整个屏幕左上角为原点qDebug() event-globalX() : event-globalY(); }         这里点击了一个PushButton左上角的位置获取的位置信息也是不一样的。         还有一点要注意的就是不管是使用鼠标左键还是右键甚至按下滚轮也可以触发这个事件。 void PushButton::mousePressEvent(QMouseEvent *event) {if (event-button() Qt::LeftButton)qDebug() 左键;else if (event-button() Qt::RightButton)qDebug() 右键;elseqDebug() 其他键;// 以PushButton左上角为原点qDebug() event-x() : event-y(); // 包含QMouseEvent头文件// 以整个屏幕为原点qDebug() event-globalX() : event-globalY(); } 释放事件 鼠标释放事件就是通过mouseReleaseEvent来捕获的。 void PushButton::mousePressEvent(QMouseEvent *event) {if (event-button() Qt::LeftButton)qDebug() 左键按下;else if (event-button() Qt::RightButton)qDebug() 右键按下;elseqDebug() 其他键按下; }void PushButton::mouseReleaseEvent(QMouseEvent *event) {if (event-button() Qt::LeftButton)qDebug() 左键释放;else if (event-button() Qt::RightButton)qDebug() 右键释放;elseqDebug() 其他键释放; } 双击事件 双击事件通过虚函数mouseDoubleClickEvent来实现。 void PushButton::mouseDoubleClickEvent(QMouseEvent *event) {if (event-button() Qt::LeftButton)qDebug() 左键双击;else if (event-button() Qt::RightButton)qDebug() 右键双击;elseqDebug() 其他键双击; }移动事件 鼠标移动事件通过mouseMoveEvent来实现为了实时捕捉鼠标位置的信息需要通过setMouseTracking方法追踪鼠标的位置。         鼠标移动不同于以上操作。随便移动鼠标就会产生大量事件当捕获这个事件时再进行一些复杂的逻辑那么程序负担就很重很容易产生卡顿等问题。         Qt 为了保证程序的流畅性默认情况下不会对鼠标移动进行追踪也就不会调用mouseMoveEvent只有在构造函数中指明当前窗口需要捕捉鼠标移动事件使用setMouseTracking方法参数设置为true。 PushButton::PushButton(QWidget* parent):QPushButton(parent) {this-setMouseTracking(true); }void PushButton::mouseMoveEvent(QMouseEvent *event) {qDebug() event-x() event-y(); }滚轮事件 Qt 中滚轮事件是通过QWheelEvent类实现的而滚轮滑动的距离可以通过delta方法获取。 void PushButton::wheelEvent(QWheelEvent *event) {qDebug() event-delta(); }         打印的值为正负120滚轮向上滚动为向下滚动为-。         现在我们可以写一个通过滚轮调节字体大小的。 void PushButton::wheelEvent(QWheelEvent *event) {QFont font this-font();qDebug() font;if (event-delta() 0)font.setPointSize(font.pointSize() 1);else if (event-delta() 0)font.setPointSize(font.pointSize() - 1);this-setFont(font); } 按键事件 Qt 中的按键事件是通过 QKeyEvent 类来实现的。按键上的按键按下或者被释放时都会触发按键事件。 单个按键 之前我们也使用过QShortCut这个是信号和槽封装的获取键盘的方式站在更底层的角度课可以通过事件获取当前用户键盘按下的情况使用的是keyPressEvent。 void MainWindow::keyPressEvent(QKeyEvent *event) {qDebug() event-key(); }         按照abcde的顺序按下键盘上的键输出的窗口就会打印这样的内容当然也可以试试别的按键想要判断还可以这样写。 void MainWindow::keyPressEvent(QKeyEvent *event) {qDebug() event-key();if (event-key() Qt::Key_A)qDebug() 按下了a键; }         还有一点要注意的是我们这里直接在QMainWindow中重写了这个事件函数也可以在QWidget中重写这个事件函数这里就要注意了想要触发这个事件一定要让该控件获取焦点也就是说焦点不在是触发不了事件的什么是焦点那就是要选中这个控件。 组合按键 想要使用组合键就要通过modifiers来获取。Qt::KeyboardModifier 中定义了在处理键盘事件是对应的修改键。 Qt::NoModifier 无修改键 Qt::ShiftModifier Shift 键 Qt::ControlModifier Crtl 键 Qt::AltModifier Alt 键 Qt::MetaModifier Meta 键Windows上指Win键 macOS上指Command键 Qt::KeypadModifier 使用数字键盘进行输入时Num Lock键处于打开状态 Qt::GroupSwitchModifier 用于在输入法之间切换 void MainWindow::keyPressEvent(QKeyEvent *event) {qDebug() event-key();if (event-key() Qt::Key_A event-modifiers() Qt::ControlModifier)qDebug() 按下了Crtl a键; } 定时器 Qt 在进行窗口程序处理的过程中经常要周期性的执行某些操作或者制作一些动画效果使用定时器就可以实现定时器就是间隔一段时间后执行某些任务。         Qt 中的定时器分为QTimerEvent和QTimer两个类 QTimerEvent类用来描述一个定时器事件使用startTimer函数来开启定时器需要输入一个以毫秒为单位的整数作为参数来表明设定的时间它返回的整型值代表一个定时器。当定时器溢出时定时时间到达就可以在timeEvent函数中获取该定时器的编号来进行相关操作。QTimer类用来实现定时器它提供了更高一层的编程接口比如可以连接信号和槽还可以设置只运行一次的定时器。         QTimer 的背后是QTimerEvent 定时器事件进行支撑的。 QTimerEvent 我们还是使用LCD Number这个控件这个控件显示的是一个数字把初始值设置为10设置一个每一秒就触发一次的定时器。 MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);// 开启定时器事件// 返回一个定时器idtimeId this-startTimer(1000); // 因为后续还要使用定义为成员变量}void MainWindow::timerEvent(QTimerEvent *event) {// 如果一个程序中存在多个定时器startTimer创建的定时器此时每个定时器都会触发这个函数// 先判断if (event-timerId() ! this-timeId) // 如果不是就忽略return;int value ui-lcdNumber-intValue();if (value 0){// 停止定时器this-killTimer(this-timeId);return;}value - 1;ui-lcdNumber-display(value); }         使用timerEvnet比QTimer还要复杂需要手动管理timerId区分这次的timerId是否正确所以后续还是使用QTimer。 QTimer QTimer 在LCD Number中使用过这里演示一下就可以了。 MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);timer new QTimer(this);timer-start(1000);connect(timer, QTimer::timeout, this, MainWindow::handle); }void MainWindow::handle() {int value ui-lcdNumber-intValue();if (value 0){timer-stop();return;}value - 1;ui-lcdNumber-display(value); }窗口事件 moveEvent 是窗口移动时触发的事件resizeEvent 是窗口大小改变时触发的事件。         拖动窗口和调整窗口大小就会打印相应的内容。 void Widget::moveEvent(QMoveEvent *event) {qDebug() event-pos(); }void Widget::resizeEvent(QResizeEvent *event) {qDebug() event-size(); } 文件 对于文件操作以及不再陌生了不管是C语言的文件操作还是C的还有Linux中提供的系统接口前面都已经介绍过了这些方法都是封装了系统的APIQt 中也提供了一套文件操作的API而且也更推荐使用这一套。 输入输出设备 在 Qt 中文件读写的类为QFile它的父类是QFileDevice这个类提供了文件交互的底层功能这个类的父类又是QIODevice在往上就是QObject。         QIODevice 是 Qt 中所有输入输出设备的基础类。 QFile用于文件操作和文件读写的类。QSaveFile用于安全保存文件的类他会把数据写入一个临时文件成功提交后再将数据写入最终文件。如果出现错误可以保证不会丢失原本的数据或者只有部分写入。QTemporaryFile用于创建临时文件的类使用QTemporaryFile::open可以创建一个文件名唯一的临时文件对象被删除时临时文件自动被删除。QTcpSocket 和 QUdpSocket实现网络通信。QSerialPort为串口通信方式一般用在嵌入式系统上。QBluetoothSocket用于蓝牙通信的类。QProcess对系统操作做的封装。QBuffer内置的缓冲区类。 文件读写类 再 Qt 中文件的读写主要是通过 QFile 类实现的。         要对数据做读取就要先打开文件。         这两个方法还需要使用C语言的方式就比较麻烦下面还有一个。         再构造函数中指定路径后直接使用这个方法就可以打开参数为OpenMode意思是打开方式有读有写还有追加写这几种方式文档中也有对应的枚举类型。         对文件的操作有读数据在QIODevice这个类中可以找到。         对文件的操作还有写数据。         最后也不要忘了关闭文件使用的是close这个方法。 现在我们就可以实现一个记事本的功能了。 MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);// 获取菜单栏QMenuBar* menuBar this-menuBar();this-setMenuBar(menuBar);// 添加菜单QMenu* menu new QMenu(文件(F));menuBar-addMenu(menu);// 添加菜单项QAction* action1 new QAction(打开);QAction* action2 new QAction(保存);menu-addAction(action1);menu-addAction(action2);// 指定一个输入框edit new QPlainTextEdit();QFont font edit-font();font.setPointSize(20);edit-setFont(font);this-setCentralWidget(edit);// 连接信号和槽connect(action1, QAction::triggered, this, MainWindow::handleAction1);connect(action2, QAction::triggered, this, MainWindow::handleAction2); }void MainWindow::handleAction1() {// 打开文件先弹出对话框QString path QFileDialog::getOpenFileName(this);// 把文件名显示到状态栏QStatusBar* statusBar this-statusBar();statusBar-showMessage(path);// 根据用户选择的路径构造一个QFile对象QFile file(path);bool ret file.open(QIODevice::ReadOnly);if (!ret){// 打开文件失败statusBar-showMessage(path 打开失败!);return;}// 读取文件QString text file.readAll(); // 虽然返回的是一个QByteArray但是转换成QString一定要确保打开的文件是文本文件// 关闭文件file.close();// 把读取到的内容显示到输入框edit-setPlainText(text); }void MainWindow::handleAction2() {// 弹出保存文件的对话框QString path QFileDialog::getSaveFileName(this);// 在状态里显示文件名QStatusBar* statusBar this-statusBar();statusBar-showMessage(path);// 根据用户选择的路径构造一个QFile对象QFile file(path);bool ret file.open(QIODevice::WriteOnly);if (!ret){statusBar-showMessage(path 打开失败!);return;}// 写入文件const QString text edit-toPlainText();file.write(text.toUtf8());// 关闭文件file.close(); }         先在QPlainTextEdit中输入一些内容点击文件再点击保存选择保存到桌面输入文件名这样就保存成功了。         关闭程序再次运行这次输入框中什么也没有点击文件再点击打开找到刚才保存的文件这样就打开成功了。 文件和目录信息类 QFileInfo 是 Qt 中提供的一个用于获取文件和目录信息的类例如获取文件名文件大小和文件修改日期等。常用的方法有 方法说明isDir文件是否为目录isExecutable文件是否为可执行程序fileName文件名completeBaseName完整的文件suffix文件名后缀completeSuffix完整的文件名后缀size文件大小isFile是否为文件fileTime获取文件创建时间、修改时间、最近访问时间 我们还是打开保存在桌面的文件就会获取我们想要的信息。 void Widget::on_pushButton_clicked() {// 打开文件获取路径QString path QFileDialog::getOpenFileName(this);// 构造一个QFileInfo对象QFileInfo fileInfo(path);// 打印qDebug() fileInfo.fileName(); // 文件名qDebug() fileInfo.suffix(); // 文件后缀qDebug() fileInfo.path(); // 文件路径qDebug() fileInfo.completeSuffix(); // 完整后缀qDebug() fileInfo.completeBaseName(); // 完整文件名 } 多线程 Qt 多线程和 Linux 中的多线程本质是一样的。在 Linux 中使用的API是Linux系统提供的pthread库Qt 也重新封装了。         Qt 中的多线程一般是通过 QThread类 实现的。QThread 代表一个程序中可以独立控制的进程也可以和进程中其他线程共享数据。 常用API 方法说明run线程入口函数。start通过调用run开始执行线程操作系统将根据优先级参数调度线程如果线程已经在运行那就忽略。currentThread返回一个指向当前线程的QThread指针。isRunning如果线程正在运行返回true反之返回false。sleep/msleep/usleep使线程休眠单位为秒/毫秒/微秒。wait 阻塞线程满足以下任何一个条件 与此 QThread 对象关联的线程已经完成执行即从run方法返回如果线程已经完成或者还没有启动都返回true。已经过了几毫秒如果时间是 ULONG_MAX默认值那么等待永远不会超时线程必须从run返回如果等待超时函数返回false。类似于 pthread_join类似的功能。 terminate终止线程执行何时终止取决于调度策略之后可以使用QThread::wait来确保finished线程结束发出该信号可以通过该信号实现线程清理工作 之前使用定时器来完成倒计时程序也可以通过线程来完成类似的功能现在创建一个新线程。因为存在线程安全的问题多个线程同时修改界面就会导致界面出错所以 Qt 要对界面的控件进行修改一定要在主线程内执行。         虽然不能修改界面但是可以计时也可以写一个类似定时器的功能。         创建一个线程类继承QThread重要的就是重写run方法使用QThread中的sleep方法可以让线程休眠一秒之后发送我们自定义的信号。         主线程要添加一个新线程对象连接信号槽并启动线程只要新线程发出信号主线程就可以捕捉到从而达成定时的效果。 class Thread : public QThread {Q_OBJECT public:Thread();void run();signals:void notify(); };// 重要是重写父类run方法 void Thread::run() {// 在新线程中不能直接修改界面内容// 每到一秒通过信号槽。通知主线程负责更新界面for (int i 0; i 10; i){sleep(1);// 发送信号通知主线程emit notify();} } class MainWindow : public QMainWindow {Q_OBJECT// ... public:void handle();private:// ...Thread thread; };MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);// 连接信号和槽通过槽函数更新界面connect(thread, Thread::notify, this, MainWindow::handle);// 启动线程thread.start(); }void MainWindow::handle() {int value ui-lcdNumber-intValue();if (value 0)return;value--;ui-lcdNumber-display(value); }         我们之前提到多线程主要还是站在服务器开发的角度考虑的就是利用了CPU多核的资源或者双路CPU从而达到高效的处理。         那么客户端多线程的意义不在这里对于客户端用户来说体验感是主要的还是要通过多线程的方式执行一些耗时的等待IO的操作避免主线程卡死比如客户端和服务端进行上传和下载一个很大的文件传输需要消耗很长时间这种密集IO操作就会使程序被系统阻塞所以只要被阻塞用户的操作也就无法响应。         所以更好的做法是使用单独的线程来处理密集IO操作主线程主要负责事件循环负责处理用户的操作。 线程安全 常用的实现线程互斥和同步的类有 互斥锁QMutex、QMutexLocker条件变量QWaitCondition信号量QSemaphore读写锁QReadLocker、QWriteLocker、QReadWriteLock 互斥锁 互斥锁是为了防止多个线程同时访问同一对象实例的方法在 Qt 中主要是通过QMutex类来处理的。         在 Linux 的章节我们也详细说过了这里我们在实现一下。 class Thread : public QThread {Q_OBJECT public:// ...static int num; // 静态成员变量 };int Thread::num 0; // 重写run方法 void Thread::run() {for (int i 0; i 50000; i){Thread::num;} }MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);// 创建两个线程对象Thread t1;Thread t2;t1.start();t2.start();// 线程等待t1.wait();t2.wait();qDebug() Thread::num; }         如果不加锁就是上面的结果两个线程同时最后的结果应该是100000。 class Thread : public QThread {Q_OBJECT public:// ...static int num;static QMutex mutex; };void Thread::run() {for (int i 0; i 50000; i){mutex.lock();num;mutex.unlock();} }         这种就是加锁和解锁但是话又说回来作为一个C程序员内存泄漏是一个很大的问题所以一定要注意unlock的问题如果代码执行过程中return了或者因为抛异常都可能导致无法调用unlock的问题同理释放内存也是这样的所以为了解决这样的问题C中就出现了智能指针同样是使用RAII的机制。Qt 中的QMutexLocker就是QMutex的智能指针。 void Thread::run() {for (int i 0; i 50000; i){QMutexLocker locker(mutex);num;} }         不管是C11中的mutex还是Qt的QMutex都是封装了系统的锁。 条件变量 多线程编程中访问临界资源一定要先检测临界资源是否存在因为检测也是访问临界资源所以在这之前就要加锁但是如果一直加锁、检测、检测失败、释放锁频繁执行这种操作也是无意义的。         所以某个线程还需要等待某些条件满足才能执行这也是Linux篇章中说过的Qt 中提供了一个QWaitCondition类解决上述问题其中wait方法是释放锁等待wake方法是加锁唤醒wakeAll是唤醒所有此外检测也是采用while循环检测的方式。 信号量 原来我们就说过信号量本质上是一个计数器在多线程场景中多个线程访问一个数量有限的资源信号量本是也是一个预定机制有两个方法分别是P操作获取信号量和V操作释放信号量在 Qt 中 QSemaphore 封装了信号量P操作和V操作变成了acquire方法和release方法。 网络 Qt 为了支持跨平台对网络编程的API也重新封装了。 网络编程其实编写的是应用层代码但是需要传输层的支持传输层的核心协议有UDP和TCPQt 也提供了两套API分别是QUdpSocket和QTcpSocket。         还有一点要注意的是要想实现网络编程还要在.pro文件中添加network模块。我们之前提到过的各种控件都包含在QtCore模块中为了不让可执行程序变得过于庞大导致一些性能不够好的机器承受太大的压力所以就进行了模块化的处理默认情况下额外的模块不会参与编译有需要就在.pro文件中添加。 UDP Socket 主要有两个类QUdpSocket 和 QNetworkDatagram。 名称类型说明 bind(const QHostAddress, quint16) 方法绑定指定的端口号类似bind。 receiveDatagram() 方法返回 QNetworkDatagram读取一个UDP数据报对标recvfrom。 writeDatagram(constQNetworkDatagram) 方法发送一个UDP数据报对标sendto。readyRead信号在收到数据并准备就绪后触发。此时就可以在槽函数中完成读取请求的操作。 QNetworkDatagram 表示一个UDP数据报。 名称类型说明 QNetworkDatagram(const QByteArray,                                  const QHostAddress,                                  quint16) 构造函数通过 QByteArray目标IP地址目标端口号 来构造一个UDP数据报。data()方法获取数据报内部持有的数据返回  QByteArray。senderAddress()方法获取数据报中包含的对端IP地址。senderPort()方法获取数据报中包含的对端的端口号。 现在我们就可以写一个回显服务器在界面中拖拽一个 QListWidget 来显示消息。         在写代码之前一定要在.pro文件中添加network模块。写一个服务器首先就要有一个Socket对象之后就要连接信号和槽捕捉readyRead信号对应的槽函数就要完成服务器的核心逻辑之后就是bind端口号一个Udp服务器就做好了。 MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);// 创建出socket这个对象socket new QUdpSocket(this);// 设置窗口标题this-setWindowTitle(服务器);// 连接信号槽connect(socket, QUdpSocket::readyRead, this, MainWindow::processRequest);// 一定是先连接信号槽再bind// 绑定的Any就类似Linux中bind的INADDR_ANY可以绑定多个网卡就可以接收不同网卡的数据bool ret socket-bind(QHostAddress::Any, 8080);if (!ret){// 绑定失败// errorString就类似于perrorQMessageBox::critical(this, 服务器启动出错, socket-errorString());return;} }         之后就是服务器的核心逻辑。 // 完成服务器的核心逻辑 void MainWindow::processRequest() {// 1. 读取请求并分析const QNetworkDatagram requestDatagram socket-receiveDatagram();const QString request requestDatagram.data(); // data返回的是QByteArray可以转换成QString// 2. 根据请求计算响应const QString response process(request);// 3. 把响应写回客户端QNetworkDatagram responseDatagram(response.toUtf8(), requestDatagram.senderAddress(), requestDatagram.senderPort());socket-writeDatagram(responseDatagram);// 显示到服务器QString log [ requestDatagram.senderAddress().toString() : QString::number(requestDatagram.senderPort()) ] req: \ request , resp: response;ui-listWidget-addItem(log); }QString MainWindow::process(const QString request) {// 由于是回显服务器请求就是响应return request; }         Udp使用的是数据报的形式所以接收要接收一个数据报对象这个数据报中有对端发来的数据和其他属性字段。给客户端进行响应的时候也要响应一个数据报构建一个数据报对象再填充数据使用toUtf8就可以把QString转换成QByteArray。最后再显示到服务器的QListWidget中就可以了。 下面就是客户端的界面了给客户端设计一个界面。有一个回显框、输入框和发送按钮。         再使用布局管理器修饰一下。         调整一下垂直布局管理器让下面的发送栏宽一点。         没有变宽就是因为没有调整下面两个控件的sizePolicy都设置成Expanding就可以了。         这些设置都是可以调整的可以按照自己喜欢的方式调整。         我们想要实现的功能是现在输入框输入内容点击发送按钮发送给服务端所以先写一个按钮的槽函数。 void MainWindow::on_pushButton_clicked() {// 获取输入框的内容const QString text ui-lineEdit-text();ui-lineEdit-setText();// 构造 UDP 的请求数据QNetworkDatagram requestDatagram(text.toUtf8(), QHostAddress(SERVER_IP), SERVER_PORT);// 发送请求数据socket-writeDatagram(requestDatagram);// 把发送的请求添加到列表框中ui-listWidget-addItem(客户端: text);}         现在客户端就有了发送的能力接下来就要写接收服务端数据的代码了。   // 两个常量描述服务器的地址和端口 const QString SERVER_IP 127.0.0.1; const quint16 SERVER_PORT 8080;MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);// 创建socket对象socket new QUdpSocket(this);// 修改标题this-setWindowTitle(客户端);// 通过信号槽处理服务端返回的数据connect(socket, QUdpSocket::readyRead, this, MainWindow::processResponse);}void MainWindow::processResponse() {// 通过这个槽函数处理收到的响应// 读取响应数据const QNetworkDatagram responseDatagram socket-receiveDatagram();const QString response responseDatagram.data();// 把响应数据显示到界面中ui-listWidget-addItem(response); }         接下来就来看一看效果让 Qt Creater 编译两个程序。 TCP Socket 核心的类有两个QTcpServer 和 QTcpSocket。QTcpServer 用于监听端口获取客户端连接。 名称类型说明 listen(const QHostAddress, quint16 port) 方法绑定指定的地址和端口号并开始监听对标 bind 和 listen。 nextPendingConnection() 方法 从系统中获取到一个已经建立好的TCP连接。 返回一个 QTcpSocket表示这个客户端的连接。 通过这个socket对象完成和客户端之间的通信。 对标accept。 newConnection 信号有新的客户端连接建立好后触发。 QTcpSocket 用户客户端额服务端之间的数据交互。 名称类型说明 readAll() 方法读取当前接收缓冲区中的所有数据返回 QByteArray 对象对标read。 write(const QByteArray ) 方法把数据写入socket对标write。 deleteLater() 方法暂时把 socket 对象标记位无效Qt 会在下个事件循环中析构释放该对象。readyRead信号有数据到达并准备就绪时触发。 disconnected 信号连接断开时触发。 方法和信号知道了下面就可以继续编写代码了客户端和服务端的界面都是不变的变得是这是一个TCP服务器除了bind还需要设置成监听状态使用listen方法就可以完成只要有新的连接就会触发newConnection信号。 class MainWindow : public QMainWindow {Q_OBJECT public:void processConnection();private:QTcpServer* tcpServer; };MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);// 修改窗口标题this-setWindowTitle(服务器);// 创建tcpServertcpServer new QTcpServer(this);// 一定要先连接信号和槽connect(tcpServer, QTcpServer::newConnection, this, MainWindow::processConnection);// bind 并且 listen这是初始化的最后一步在这之前一定要做好准备bool ret tcpServer-listen(QHostAddress::Any, 8080);if (!ret){QMessageBox::critical(this, 服务器启动失败!, tcpServer-errorString());exit(1);} }         接下来就是设置好listen状态后触发了newConnection信号之后执行processConnection的操作。 class MainWindow : public QMainWindow {Q_OBJECTpublic:void processConnection();QString process(const QString request); private:QTcpServer* tcpServer; };void MainWindow::processConnection() {// 通过 tcpServer 拿到一个socket对象通过这个对象和客户端进行通信QTcpSocket* clientSocket tcpServer-nextPendingConnection();QString log [ clientSocket-peerAddress().toString() : QString::number(clientSocket-peerPort()) ] 客户端上线; // peerAddress 表示对端的IP地址ui-listWidget-addItem(log);// 通过信号和槽处理客户端发来的请求connect(clientSocket, QTcpSocket::readyRead, this, [](){// 读取请求数据QString request clientSocket-readAll();// 根据请求处理响应const QString response process(request);// 写回响应数据clientSocket-write(response.toUtf8());// 显示到界面中QString log [ clientSocket-peerAddress().toString() : QString::number(clientSocket-peerPort()) ] \ req: request , resp: response;ui-listWidget-addItem(log);});// 如果客户端断开连接也是要处理的还是通过信号槽的方式connect(clientSocket, QTcpSocket::disconnected, this, [](){// 显示断开连接的日志QString log [ clientSocket-peerAddress().toString() : QString::number(clientSocket-peerPort()) ] 客户端断开连接;ui-listWidget-addItem(log);// 释放socket// delete clientSocket; // 一旦delete就代表clientSocket不能使用了它一定得是最后一步但是有可能被return和抛异常跳过clientSocket-deleteLater(); // 这个操作就不会立即释放socket而是在下一轮事件循环中再释放槽函数都是在事件循环中执行的。}); }QString MainWindow::process(const QString request) {return request; // 因为是回显服务器所以直接返回 }         服务端的逻辑就写完了但是这是TCP服务器与UDP不同的是TCP是面向字节流的并不能确定发过来的就是一个完整的报文所以还需要一些其他操作因为是回显服务器这里也就不写了如果想要知道如何做可以看网络专栏中的应用层协议篇章那里讲解了如何序列化和反序列化等操作。 下面就是客户端的代码了除了要维护连接编写上和Udp客户端没有太大的差别。 const QString SERVER_IP 127.0.0.1; const quint16 SERVER_PORT 8080;MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);// 设置窗口标题this-setWindowTitle(客户端);// 创建socket对象因为是客户端只有一个socket对象socket new QTcpSocket(this);// 建立与服务端的连接socket-connectToHost(SERVER_IP, SERVER_PORT);// 连接信号槽connect(socket, QTcpSocket::readyRead, this, [](){// 读取服务端的响应QString response socket-readAll();// 显示到listWidget中ui-listWidget-addItem(服务端: response);});// 阻塞式等待连接建立结果if (!socket-waitForConnected()){QMessageBox::critical(this, 连接服务器失败!, socket-errorString());exit(1);} }void MainWindow::on_pushButton_clicked() {// 获取输入框中的内容const QString text ui-lineEdit-text();ui-lineEdit-setText();// 发送数据socket-write(text.toUtf8());// 把发送的数据添加到ListWidgetui-listWidget-addItem(客户端: text); }         代码写完了下面就来看一下效果。 HTTP Client 进行 Qt 开发时和服务器之间的通信很多时候也会用到HTTP协议通过HTTP向服务器提交数据或者通过HTTP从服务器获取数据。HTTP相比TCP/UDP还要使用的更多一点而HTTP协议本质上是基于TCP协议实现的也就是封装了TcpSocket。         Qt 只是提供了 HTTP客户端并没有提供服务端         下面是核心API三个类分别是QNetworkAccessManagerQNetworkRequestQNetworkReply。 QNetworkAccessManager 提供了HTTP的核心操作。 方法说明 get(const QNetworkRequest ) 发起一个 HTTP GET 请求返回 QNetworkReply 对象。 post(const QNetworkRequest , const QByteArray ) 发起一个 HTTP POST 请求返回 QNetworkReply 对象。 QNetworkRequest 表示一个 HTTP 请求不包含请求正文 body想要发送一个带有body的请求需要再QNetworkAccessManager的post方法中的参数传入body。 方法说明 QNetworkRequest(const QUrl ) 通过 URL 构造一个 HTTP 请求。 setHeader(QNetworkRequest::KnownHeaders header,                   const QVariant value) 设置请求头。 其中 QNetworkRequest::KnownHeaders 是一个枚举类型常用取值为 取值说明 ContentTypeHeader 描述 body 的类型。 ContentLengthHeader 表述 body 的长度。 LocationHeader 用于重定向报文中指定的重定向地址。 CookieHeader 设置 Cookie UserAgentHeader 设置 User-Agent QNetworkReply 表示一个 HTTP响应这个类同时也是 QIODevice 的子类。QNetworkReply 还有一个重要的信号 finishied在客户端收到完整的响应数据后触发。 方法说明 error() 获取出错状态。 errorString() 获取出错原因的文本。 readAll() 读取响应的文本。 header(QNetworkRequest::KnownHeaders header) 读取响应指定 header 的值。 需要使用的API介绍完了下面就来写一个HTTP客户端使用的界面与上面的差不多通过指定一个Url发送请求响应的结构大概率是一个 HTML这里使用的是 QPlainTextEdit 来表示。         现在构造函数中设置一下标题并new一个 QNetworkAccessManager 对象之后就可以写槽函数了。 MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);// 设置窗口标题this-setWindowTitle(客户端);manager new QNetworkAccessManager(this); }void MainWindow::on_pushButton_clicked() {// 获取输入框的UrlQUrl url(ui-lineEdit-text());// 构造 HTTP 请求对象QNetworkRequest request(url);// 发送请求QNetworkReply* response manager-get(request);// 因为get本身并不是阻塞函数它只负责发请求不负责等待响应需要编写finishied信号的槽函数connect(response, QNetworkReply::finished, this, [](){if (response-error() QNetworkReply::NoError){// 响应已经获取到QString html response-readAll();ui-plainTextEdit-setPlainText(html);}else{// 响应出错ui-plainTextEdit-setPlainText(response-errorString());}// 释放Responseresponse-deleteLater();}); }代码写完了就可以看一下效果输入一个Url就会返回一个html格式的文本。 Qt 音视频 Qt 音频 在 Qt 中音频主要通过 QSound 类来实现。但是需要注意的是 QSound 类只支持播放 wav 格式的音频文件。在这之前也需要先引入 multimedia 模块最核心的API就是play方法用来播放音频。         在界面中添加一个按钮命名为播放当我们点击按钮就会播放音乐。首先要有一个wav后缀的文件像这种文件还是使用qrc来保存。 class MainWindow : public QMainWindow {Q_OBJECTprivate slots:void on_pushButton_clicked();private:QSound* sound; };MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);sound new QSound(:/music/zjl_qingtian.wav, this); }void MainWindow::on_pushButton_clicked() {// 在这里进行音频播放sound-play(); } Qt 视频 在 Qt 中视频播放的功能主要是通过 QMediaPlayer类 和 QVideoWidget类 来实现。在使用这两个类时要添加对应的模块multimedia 和 multimediawidgets。它也有核心的API 方法说明setMedia()设置当前媒体源。setVideoOutput() 将 QVideoWidget 视频输出附加到媒体播放器。 如果媒体播放器已经附加了视频输出将更换一个新的。 首先我们先定义几个成员变量。 class Widget : public QWidget {Q_OBJECT public:// ... private:Ui::Widget *ui;QMediaPlayer *mediaPlayer; // 播放声音QVideoWidget *videoWidget; // 显示视频//创建两个按钮选择视频按钮和播放按钮QPushButton *chooseBtn, *playBtn; };         接下来就是设置视频播放窗口的代码。 Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui-setupUi(this);// 对象实例化mediaPlayer new QMediaPlayer(this);videoWidget new QVideoWidget(this);// 设置播放窗口videoWidget-setMinimumSize(600, 600);// 垂直布局QVBoxLayout *vbox new QVBoxLayout();this-setLayout(vbox);// 实例化按钮chooseBtn new QPushButton(选择视频, this);playBtn new QPushButton(this);// 设置图标playBtn-setIcon(style()-standardIcon(QStyle::SP_MediaPlay));// 创建水平布局QHBoxLayout* hbox new QHBoxLayout();hbox-addWidget(chooseBtn);hbox-addWidget(playBtn);// 添加到垂直布局管理器中vbox-addWidget(videoWidget);vbox-addLayout(hbox);connect(chooseBtn, QPushButton::clicked, this, [](){// 选择视频返回视频的路径QString url QFileDialog::getOpenFileName(this, 选择视频);// 设置声音mediaPlayer-setMedia(QUrl(url));// 输出画面mediaPlayer-setVideoOutput(videoWidget);// 播放mediaPlayer-play();}); }         之后运行就可以选择播放视频了但是第一次运行可能出现一些不能播放的问题这里各位可以自行查找解决的方案也并不复杂。
http://www.zqtcl.cn/news/710084/

相关文章:

  • 成都高新区规划建设局网站网络营销方式有哪些?举例说明
  • 国家企业信用公信系统入口seo服务
  • 个人网站网页模板室内装修设计自学软件
  • 什么网站可以做告白的网页网站模板套用湖南岚鸿
  • 膜结构网站推广怎么做怎样把网站上传到空间
  • 三维网站是怎么做的商城网站 运营
  • 程序员网站开发框架无锡网络公司网站建设app微信公众号平
  • 中关村网站建设网络营销策划书范文
  • 电商网站建设与课程设计科技网站模版
  • 建设部网站资质漳州最专业的网站建设公司
  • 网站建设需求和页面需求怎么提一个静态网站怎么做
  • 宝塔wordpress广州网站营销seo
  • 甘肃城乡建设厅网站首页发布公司信息的网站
  • 工信部网站备案查询 手机凡科网微信小程序制作
  • 一站多通怎么做网站网站推广工具 刷链接
  • 学生做网站的工作室网络舆情监测与研判考试重点
  • 做网站去哪个公司好广告创意设计论文
  • 20m带宽做网站够用吗win7创建wordpress
  • qq音乐怎么做mp3下载网站发卡网站建设方案
  • 做cpc不做网站可以吗网站跳出率
  • 公司网站变更域名有了域名就可以做网站了吗
  • 网站建设推广营销策划做外贸网站需要注册公司吗
  • 可信赖的赣州网站建设做羽毛球网站
  • 如何找网站做推广wordpress登录及注册
  • 韩国美容网站 模板wordpress中英文
  • 为什么邮箱突然进不去了总提示正在进入不安全网站wordpress需注册访问
  • 建网站哪家最好山东泰安房价
  • wordpress4.9+多站点网络推广公司联系昔年下拉
  • 西安seo网站关键词优化罗田县建设局网站
  • 北京网站建设 shwllnmp新手 wordpress