瀏覽代碼

V1.6.0

1.播放器界面美化
叶海辉 6 年之前
父節點
當前提交
a57eff0357
共有 60 個文件被更改,包括 5345 次插入1408 次删除
  1. 14 3
      VideoPlayer.pro
  2. 二進制
      image/open_focus.png
  3. 二進制
      image/open_normal.png
  4. 二進制
      image/pause1_normal.png
  5. 二進制
      image/pause_focus.png
  6. 二進制
      image/pause_normal.png
  7. 二進制
      image/start1_normal.png
  8. 二進制
      image/start_focus.png
  9. 二進制
      image/start_normal.png
  10. 二進制
      main.aps
  11. 二進制
      main.ico
  12. 32 0
      main.rc
  13. 12 0
      resources.qrc
  14. 23 0
      src/CustomTitleWidget/CustomTitleWidget.pri
  15. 138 0
      src/CustomTitleWidget/customtitle.cpp
  16. 57 0
      src/CustomTitleWidget/customtitle.h
  17. 297 0
      src/CustomTitleWidget/customtitle.ui
  18. 113 0
      src/CustomTitleWidget/frmmain.cpp
  19. 49 0
      src/CustomTitleWidget/frmmain.h
  20. 508 0
      src/CustomTitleWidget/frmmain.ui
  21. 77 0
      src/CustomTitleWidget/frmmessagebox.cpp
  22. 35 0
      src/CustomTitleWidget/frmmessagebox.h
  23. 275 0
      src/CustomTitleWidget/frmmessagebox.ui
  24. 24 0
      src/CustomTitleWidget/iconhelper.cpp
  25. 37 0
      src/CustomTitleWidget/iconhelper.h
  26. 二進制
      src/CustomTitleWidget/image/add-line_horizontal.png
  27. 二進制
      src/CustomTitleWidget/image/add-line_vertical.png
  28. 二進制
      src/CustomTitleWidget/image/array_down.png
  29. 354 0
      src/CustomTitleWidget/image/black.css
  30. 350 0
      src/CustomTitleWidget/image/blue.css
  31. 二進制
      src/CustomTitleWidget/image/checkbox_checked.png
  32. 二進制
      src/CustomTitleWidget/image/checkbox_unchecked.png
  33. 二進制
      src/CustomTitleWidget/image/error.png
  34. 二進制
      src/CustomTitleWidget/image/fontawesome-webfont.ttf
  35. 353 0
      src/CustomTitleWidget/image/gray.css
  36. 二進制
      src/CustomTitleWidget/image/info.png
  37. 347 0
      src/CustomTitleWidget/image/navy.css
  38. 二進制
      src/CustomTitleWidget/image/qt_zh_CN.qm
  39. 二進制
      src/CustomTitleWidget/image/question.png
  40. 二進制
      src/CustomTitleWidget/image/radio_normal.png
  41. 二進制
      src/CustomTitleWidget/image/radio_selected.png
  42. 二進制
      src/CustomTitleWidget/image/sub-line_horizontal.png
  43. 二進制
      src/CustomTitleWidget/image/sub-line_vertical.png
  44. 121 0
      src/CustomTitleWidget/myhelper.h
  45. 22 0
      src/CustomTitleWidget/rc.qrc
  46. 14 6
      src/main.cpp
  47. 0 156
      src/mainwindow.cpp
  48. 0 53
      src/mainwindow.h
  49. 0 142
      src/mainwindow.ui
  50. 110 932
      src/videoplayer/videoplayer.cpp
  51. 26 114
      src/videoplayer/videoplayer.h
  52. 438 0
      src/videoplayer/videoplayer.ui
  53. 50 0
      src/videoplayer/videoplayer_showvideowidget.cpp
  54. 43 0
      src/videoplayer/videoplayer_showvideowidget.h
  55. 21 0
      src/videoplayer/videoplayer_showvideowidget.ui
  56. 1022 0
      src/videoplayer/videoplayer_thread.cpp
  57. 151 0
      src/videoplayer/videoplayer_thread.h
  58. 177 0
      src/videoplayer/widget/VideoSlider.cpp
  59. 53 0
      src/videoplayer/widget/VideoSlider.h
  60. 2 2
      说明.txt

+ 14 - 3
VideoPlayer.pro

@@ -11,17 +11,23 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
 TARGET = VideoPlayer
 TEMPLATE = app
 
+include(src/CustomTitleWidget/CustomTitleWidget.pri)
 
 SOURCES += src/main.cpp \
+    src/videoplayer/videoplayer_thread.cpp \
     src/videoplayer/videoplayer.cpp \
-    src/mainwindow.cpp
+    src/videoplayer/videoplayer_showvideowidget.cpp \
+    src/videoplayer/widget/VideoSlider.cpp
 
 HEADERS  += \
+    src/videoplayer/videoplayer_thread.h \
     src/videoplayer/videoplayer.h \
-    src/mainwindow.h
+    src/videoplayer/videoplayer_showvideowidget.h \
+    src/videoplayer/widget/VideoSlider.h
 
 FORMS    += \
-    src/mainwindow.ui
+    src/videoplayer/videoplayer.ui \
+    src/videoplayer/videoplayer_showvideowidget.ui
 
 
 INCLUDEPATH += $$PWD/ffmpeg/include \
@@ -37,3 +43,8 @@ LIBS += $$PWD/ffmpeg/lib/avcodec.lib \
         $$PWD/ffmpeg/lib/swresample.lib \
         $$PWD/ffmpeg/lib/swscale.lib \
         $$PWD/SDL2/lib/x86/SDL2.lib
+
+RESOURCES += \
+    resources.qrc
+
+win32:RC_FILE=$$PWD/main.rc

二進制
image/open_focus.png


二進制
image/open_normal.png


二進制
image/pause1_normal.png


二進制
image/pause_focus.png


二進制
image/pause_normal.png


二進制
image/start1_normal.png


二進制
image/start_focus.png


二進制
image/start_normal.png


二進制
main.aps


二進制
main.ico


+ 32 - 0
main.rc

@@ -0,0 +1,32 @@
+#include "winver.h"
+
+IDI_ICON1       ICON      "main.ico"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION    1,0,0,0
+ PRODUCTVERSION 1,0,0,0
+ FILEFLAGS      0x0L
+ FILEFLAGSMASK  0x3fL
+ FILEOS         VOS_NT_WINDOWS32
+ FILETYPE       VFT_APP
+ FILESUBTYPE    VFT2_UNKNOWN
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "000004b0"
+        BEGIN
+            VALUE "CompanyName", "云巅软件科技 kk.yundiantech.com"
+            VALUE "FileDescription", "KK遥控-手机控制电脑"
+            VALUE "FileVersion", "1.0.0"
+            VALUE "LegalCopyright", "云巅软件科技 kk.yundiantech.com"
+            VALUE "InternalName", "KK遥控-手机控制电脑"
+            VALUE "OriginalFilename", "KK遥控-手机控制电脑"
+            VALUE "ProductName", "KK遥控-手机控制电脑"
+            VALUE "ProductVersion", "1.0.0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x0, 1200
+    END
+END

+ 12 - 0
resources.qrc

@@ -0,0 +1,12 @@
+<RCC>
+    <qresource prefix="/">
+        <file>image/open_focus.png</file>
+        <file>image/open_normal.png</file>
+        <file>image/pause_focus.png</file>
+        <file>image/pause_normal.png</file>
+        <file>image/pause1_normal.png</file>
+        <file>image/start_focus.png</file>
+        <file>image/start_normal.png</file>
+        <file>image/start1_normal.png</file>
+    </qresource>
+</RCC>

+ 23 - 0
src/CustomTitleWidget/CustomTitleWidget.pri

@@ -0,0 +1,23 @@
+
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+
+SOURCES += \
+        $$PWD/frmmain.cpp \
+    $$PWD/iconhelper.cpp \
+    $$PWD/frmmessagebox.cpp \
+    src/CustomTitleWidget/customtitle.cpp
+
+HEADERS  += $$PWD/frmmain.h \
+    $$PWD/iconhelper.h \
+    $$PWD/frmmessagebox.h \
+    $$PWD/myhelper.h \
+    src/CustomTitleWidget/customtitle.h
+
+FORMS    += $$PWD/frmmain.ui \
+    $$PWD/frmmessagebox.ui \
+    src/CustomTitleWidget/customtitle.ui
+
+
+RESOURCES += \
+    $$PWD/rc.qrc

+ 138 - 0
src/CustomTitleWidget/customtitle.cpp

@@ -0,0 +1,138 @@
+#include "customtitle.h"
+#include "ui_customtitle.h"
+
+#include "iconhelper.h"
+#include "myhelper.h"
+
+CustomTitle::CustomTitle(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::CustomTitle)
+{
+    ui->setupUi(this);
+
+//    myHelper::FormInCenter(this);
+    this->InitStyle();
+
+    dialog = new QDialog;
+    ui->verticalLayout_content->addWidget(dialog);
+    dialog->show();
+}
+
+CustomTitle::~CustomTitle()
+{
+    delete ui;
+}
+
+void CustomTitle::doClose()
+{
+    close();
+}
+
+QWidget *CustomTitle::getContentWidget()
+{
+    return ui->widget;
+}
+
+QDialog *CustomTitle::getContentDialog()
+{
+    return dialog;
+}
+
+void CustomTitle::InitStyle()
+{
+    //设置窗体标题栏隐藏
+    this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
+    this->setAttribute(Qt::WA_TranslucentBackground, true);
+    location = this->geometry();
+    max = false;
+    mousePressed = false;
+
+    //安装事件监听器,让标题栏识别鼠标双击
+    ui->lab_Title->installEventFilter(this);
+
+    IconHelper::Instance()->SetIcon(ui->btnMenu_Close, QChar(0xf00d), 10);
+    IconHelper::Instance()->SetIcon(ui->btnMenu_Max, QChar(0xf096), 10);
+    IconHelper::Instance()->SetIcon(ui->btnMenu_Min, QChar(0xf068), 10);
+    IconHelper::Instance()->SetIcon(ui->btnMenu, QChar(0xf0c9), 10);
+    IconHelper::Instance()->SetIcon(ui->lab_Ico, QChar(0xf015), 12);
+}
+
+bool CustomTitle::eventFilter(QObject *obj, QEvent *event)
+{
+    if (event->type() == QEvent::MouseButtonDblClick) {
+        this->on_btnMenu_Max_clicked();
+        return true;
+    }
+    return QObject::eventFilter(obj, event);
+}
+
+void CustomTitle::mouseMoveEvent(QMouseEvent *e)
+{
+    if (mousePressed && (e->buttons() && Qt::LeftButton) && !max) {
+        this->move(e->globalPos() - mousePoint);
+        e->accept();
+    }
+}
+
+void CustomTitle::mousePressEvent(QMouseEvent *e)
+{
+    if (e->button() == Qt::LeftButton) {
+        mousePressed = true;
+        mousePoint = e->globalPos() - this->pos();
+        e->accept();
+    }
+}
+
+void CustomTitle::mouseReleaseEvent(QMouseEvent *)
+{
+    mousePressed = false;
+}
+
+void CustomTitle::mouseDoubleClickEvent(QMouseEvent *e)
+{
+    on_btnMenu_Max_clicked();
+}
+
+void CustomTitle::on_btnMenu_Close_clicked()
+{
+//    qApp->exit();
+    doClose();
+}
+
+void CustomTitle::on_btnMenu_Max_clicked()
+{
+    if (max) {
+        this->setGeometry(location);
+        IconHelper::Instance()->SetIcon(ui->btnMenu_Max, QChar(0xf096), 10);
+        ui->btnMenu_Max->setToolTip("最大化");
+    } else {
+        location = this->geometry();
+        this->setGeometry(qApp->desktop()->availableGeometry());
+        IconHelper::Instance()->SetIcon(ui->btnMenu_Max, QChar(0xf079), 10);
+        ui->btnMenu_Max->setToolTip("还原");
+    }
+    max = !max;
+}
+
+void CustomTitle::on_btnMenu_Min_clicked()
+{
+    this->showMinimized();
+}
+
+void CustomTitle::setTitle(QString str)
+{
+    ui->lab_Title->setText(str);
+    this->setWindowTitle(str);
+}
+
+void CustomTitle::showMaximized()
+{
+    this->show();
+    max = false;
+    on_btnMenu_Max_clicked();
+}
+
+void CustomTitle::changeMax()
+{
+    on_btnMenu_Max_clicked();
+}

+ 57 - 0
src/CustomTitleWidget/customtitle.h

@@ -0,0 +1,57 @@
+#ifndef CUSTOMTITLE_H
+#define CUSTOMTITLE_H
+
+#include <QDialog>
+
+namespace Ui {
+class CustomTitle;
+}
+
+class CustomTitle : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit CustomTitle(QWidget *parent = 0);
+    ~CustomTitle();
+
+    QWidget *getContentWidget();
+    QDialog *getContentDialog();
+
+    void setTitle(QString str);
+
+    void showMaximized();
+
+    void changeMax();
+
+    virtual void doClose();
+
+protected:
+    bool eventFilter(QObject *obj, QEvent *event);
+    void mouseMoveEvent(QMouseEvent *e);
+    void mousePressEvent(QMouseEvent *e);
+    void mouseReleaseEvent(QMouseEvent *);
+    void mouseDoubleClickEvent(QMouseEvent *e);
+
+private slots:
+    void on_btnMenu_Close_clicked();
+
+    void on_btnMenu_Max_clicked();
+
+    void on_btnMenu_Min_clicked();
+
+private:
+    Ui::CustomTitle *ui;
+
+    QPoint mousePoint;
+    bool mousePressed;
+    bool max;
+    QRect location;
+
+    QDialog *dialog;
+
+    void InitStyle();
+
+};
+
+#endif // CUSTOMTITLE_H

+ 297 - 0
src/CustomTitleWidget/customtitle.ui

@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CustomTitle</class>
+ <widget class="QDialog" name="CustomTitle">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>642</width>
+    <height>466</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>frmMain</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true"/>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widget_frame" native="true">
+     <property name="styleSheet">
+      <string notr="true">QWidget#widget_frame
+{
+background-color: rgba(0, 0, 0, 30);
+}</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="margin">
+       <number>3</number>
+      </property>
+      <item>
+       <widget class="QWidget" name="widget_back" native="true">
+        <property name="styleSheet">
+         <string notr="true"/>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_4">
+         <property name="spacing">
+          <number>0</number>
+         </property>
+         <property name="margin">
+          <number>1</number>
+         </property>
+         <item>
+          <widget class="QWidget" name="widget_title" native="true">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>100</width>
+             <height>60</height>
+            </size>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_2">
+            <property name="spacing">
+             <number>0</number>
+            </property>
+            <property name="margin">
+             <number>0</number>
+            </property>
+            <item>
+             <widget class="QLabel" name="lab_Ico">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="minimumSize">
+               <size>
+                <width>60</width>
+                <height>60</height>
+               </size>
+              </property>
+              <property name="text">
+               <string/>
+              </property>
+              <property name="alignment">
+               <set>Qt::AlignCenter</set>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QLabel" name="lab_Title">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="styleSheet">
+               <string notr="true">font: 10pt &quot;微软雅黑&quot;;
+font-size:20px;
+font-weight:bold;</string>
+              </property>
+              <property name="text">
+               <string>我的播放器</string>
+              </property>
+              <property name="alignment">
+               <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QWidget" name="widget_menu" native="true">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <layout class="QHBoxLayout" name="horizontalLayout">
+               <property name="spacing">
+                <number>0</number>
+               </property>
+               <property name="margin">
+                <number>0</number>
+               </property>
+               <item>
+                <widget class="QPushButton" name="btnMenu">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="minimumSize">
+                  <size>
+                   <width>31</width>
+                   <height>0</height>
+                  </size>
+                 </property>
+                 <property name="cursor">
+                  <cursorShape>ArrowCursor</cursorShape>
+                 </property>
+                 <property name="focusPolicy">
+                  <enum>Qt::NoFocus</enum>
+                 </property>
+                 <property name="toolTip">
+                  <string>菜单</string>
+                 </property>
+                 <property name="text">
+                  <string/>
+                 </property>
+                 <property name="flat">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QPushButton" name="btnMenu_Min">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="minimumSize">
+                  <size>
+                   <width>31</width>
+                   <height>0</height>
+                  </size>
+                 </property>
+                 <property name="cursor">
+                  <cursorShape>ArrowCursor</cursorShape>
+                 </property>
+                 <property name="focusPolicy">
+                  <enum>Qt::NoFocus</enum>
+                 </property>
+                 <property name="toolTip">
+                  <string>最小化</string>
+                 </property>
+                 <property name="text">
+                  <string/>
+                 </property>
+                 <property name="flat">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QPushButton" name="btnMenu_Max">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="minimumSize">
+                  <size>
+                   <width>31</width>
+                   <height>0</height>
+                  </size>
+                 </property>
+                 <property name="cursor">
+                  <cursorShape>ArrowCursor</cursorShape>
+                 </property>
+                 <property name="focusPolicy">
+                  <enum>Qt::NoFocus</enum>
+                 </property>
+                 <property name="toolTip">
+                  <string>最大化</string>
+                 </property>
+                 <property name="text">
+                  <string/>
+                 </property>
+                 <property name="flat">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QPushButton" name="btnMenu_Close">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="minimumSize">
+                  <size>
+                   <width>40</width>
+                   <height>0</height>
+                  </size>
+                 </property>
+                 <property name="cursor">
+                  <cursorShape>ArrowCursor</cursorShape>
+                 </property>
+                 <property name="focusPolicy">
+                  <enum>Qt::NoFocus</enum>
+                 </property>
+                 <property name="toolTip">
+                  <string>关闭</string>
+                 </property>
+                 <property name="text">
+                  <string/>
+                 </property>
+                 <property name="flat">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QWidget" name="widget" native="true">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <layout class="QVBoxLayout" name="verticalLayout_3">
+            <property name="spacing">
+             <number>0</number>
+            </property>
+            <property name="margin">
+             <number>0</number>
+            </property>
+            <item>
+             <layout class="QVBoxLayout" name="verticalLayout_content"/>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+</ui>

+ 113 - 0
src/CustomTitleWidget/frmmain.cpp

@@ -0,0 +1,113 @@
+#include "frmmain.h"
+#include "ui_frmmain.h"
+#include "iconhelper.h"
+#include "myhelper.h"
+
+frmMain::frmMain(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::frmMain)
+{
+    ui->setupUi(this);
+
+    myHelper::FormInCenter(this);
+    this->InitStyle();
+}
+
+frmMain::~frmMain()
+{
+    delete ui;
+}
+
+void frmMain::InitStyle()
+{
+    //设置窗体标题栏隐藏
+    this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
+    location = this->geometry();
+    max = false;
+    mousePressed = false;
+
+    //安装事件监听器,让标题栏识别鼠标双击
+    ui->lab_Title->installEventFilter(this);
+
+    IconHelper::Instance()->SetIcon(ui->btnMenu_Close, QChar(0xf00d), 10);
+    IconHelper::Instance()->SetIcon(ui->btnMenu_Max, QChar(0xf096), 10);
+    IconHelper::Instance()->SetIcon(ui->btnMenu_Min, QChar(0xf068), 10);
+    IconHelper::Instance()->SetIcon(ui->btnMenu, QChar(0xf0c9), 10);
+    IconHelper::Instance()->SetIcon(ui->lab_Ico, QChar(0xf015), 12);
+}
+
+bool frmMain::eventFilter(QObject *obj, QEvent *event)
+{
+    if (event->type() == QEvent::MouseButtonDblClick) {
+        this->on_btnMenu_Max_clicked();
+        return true;
+    }
+    return QObject::eventFilter(obj, event);
+}
+
+void frmMain::mouseMoveEvent(QMouseEvent *e)
+{
+    if (mousePressed && (e->buttons() && Qt::LeftButton) && !max) {
+        this->move(e->globalPos() - mousePoint);
+        e->accept();
+    }
+}
+
+void frmMain::mousePressEvent(QMouseEvent *e)
+{
+    if (e->button() == Qt::LeftButton) {
+        mousePressed = true;
+        mousePoint = e->globalPos() - this->pos();
+        e->accept();
+    }
+}
+
+void frmMain::mouseReleaseEvent(QMouseEvent *)
+{
+    mousePressed = false;
+}
+
+void frmMain::on_btnMenu_Close_clicked()
+{
+    qApp->exit();
+}
+
+void frmMain::on_btnMenu_Max_clicked()
+{
+    if (max) {
+        this->setGeometry(location);
+        IconHelper::Instance()->SetIcon(ui->btnMenu_Max, QChar(0xf096), 10);
+        ui->btnMenu_Max->setToolTip("最大化");
+    } else {
+        location = this->geometry();
+        this->setGeometry(qApp->desktop()->availableGeometry());
+        IconHelper::Instance()->SetIcon(ui->btnMenu_Max, QChar(0xf079), 10);
+        ui->btnMenu_Max->setToolTip("还原");
+    }
+    max = !max;
+}
+
+void frmMain::on_btnMenu_Min_clicked()
+{
+    this->showMinimized();
+}
+
+void frmMain::on_pushButton_clicked()
+{
+    myHelper::ShowMessageBoxInfo("恭喜你获得我公司送出的1000万元大礼一份!");
+}
+
+void frmMain::on_pushButton_2_clicked()
+{
+    int result = myHelper::ShowMessageBoxQuesion("确定真的不要我了吗?");
+    if (result == 1) {
+        myHelper::ShowMessageBoxInfo("你好狠心啊!");
+    } else {
+        myHelper::ShowMessageBoxInfo("亲爱的,我就知道你不会离开我的!");
+    }
+}
+
+void frmMain::on_pushButton_3_clicked()
+{
+    myHelper::ShowMessageBoxError("天空飘来五个字!");
+}

+ 49 - 0
src/CustomTitleWidget/frmmain.h

@@ -0,0 +1,49 @@
+#ifndef FRMMAIN_H
+#define FRMMAIN_H
+
+#include <QDialog>
+
+namespace Ui {
+class frmMain;
+}
+
+class frmMain : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit frmMain(QWidget *parent = 0);
+    ~frmMain();
+
+protected:
+    bool eventFilter(QObject *obj, QEvent *event);
+    void mouseMoveEvent(QMouseEvent *e);
+    void mousePressEvent(QMouseEvent *e);
+    void mouseReleaseEvent(QMouseEvent *);
+
+private slots:
+    void on_btnMenu_Close_clicked();
+
+    void on_btnMenu_Max_clicked();
+
+    void on_btnMenu_Min_clicked();
+
+    void on_pushButton_clicked();
+
+    void on_pushButton_2_clicked();
+
+    void on_pushButton_3_clicked();
+
+private:
+    Ui::frmMain *ui;
+
+    QPoint mousePoint;
+    bool mousePressed;
+    bool max;
+    QRect location;
+
+    void InitStyle();
+
+};
+
+#endif // FRMMAIN_H

+ 508 - 0
src/CustomTitleWidget/frmmain.ui

@@ -0,0 +1,508 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>frmMain</class>
+ <widget class="QDialog" name="frmMain">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>656</width>
+    <height>527</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>frmMain</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widget_title" native="true">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>100</width>
+       <height>33</height>
+      </size>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="lab_Ico">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>30</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string/>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="lab_Title">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="styleSheet">
+         <string notr="true">font: 10pt &quot;微软雅黑&quot;;</string>
+        </property>
+        <property name="text">
+         <string>自定义UI演示(作者:刘典武 QQ:517216493)</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget_menu" native="true">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <property name="spacing">
+          <number>0</number>
+         </property>
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QPushButton" name="btnMenu">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>31</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="cursor">
+            <cursorShape>ArrowCursor</cursorShape>
+           </property>
+           <property name="focusPolicy">
+            <enum>Qt::NoFocus</enum>
+           </property>
+           <property name="toolTip">
+            <string>菜单</string>
+           </property>
+           <property name="text">
+            <string/>
+           </property>
+           <property name="flat">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="btnMenu_Min">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>31</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="cursor">
+            <cursorShape>ArrowCursor</cursorShape>
+           </property>
+           <property name="focusPolicy">
+            <enum>Qt::NoFocus</enum>
+           </property>
+           <property name="toolTip">
+            <string>最小化</string>
+           </property>
+           <property name="text">
+            <string/>
+           </property>
+           <property name="flat">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="btnMenu_Max">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>31</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="cursor">
+            <cursorShape>ArrowCursor</cursorShape>
+           </property>
+           <property name="focusPolicy">
+            <enum>Qt::NoFocus</enum>
+           </property>
+           <property name="toolTip">
+            <string>最大化</string>
+           </property>
+           <property name="text">
+            <string/>
+           </property>
+           <property name="flat">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="btnMenu_Close">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>40</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="cursor">
+            <cursorShape>ArrowCursor</cursorShape>
+           </property>
+           <property name="focusPolicy">
+            <enum>Qt::NoFocus</enum>
+           </property>
+           <property name="toolTip">
+            <string>关闭</string>
+           </property>
+           <property name="text">
+            <string/>
+           </property>
+           <property name="flat">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_main" native="true">
+     <property name="styleSheet">
+      <string notr="true">font: 10pt &quot;微软雅黑&quot;;</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_3">
+        <item>
+         <widget class="QLineEdit" name="lineEdit">
+          <property name="text">
+           <string>今天天气不错</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QPushButton" name="pushButton">
+          <property name="minimumSize">
+           <size>
+            <width>100</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="text">
+           <string>信息框</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QPushButton" name="pushButton_2">
+          <property name="minimumSize">
+           <size>
+            <width>100</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="text">
+           <string>询问框</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QPushButton" name="pushButton_3">
+          <property name="minimumSize">
+           <size>
+            <width>100</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="text">
+           <string>错误框</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <widget class="QGroupBox" name="groupBox">
+        <property name="title">
+         <string/>
+        </property>
+        <layout class="QHBoxLayout" name="horizontalLayout_4">
+         <item>
+          <widget class="QRadioButton" name="radioButton">
+           <property name="text">
+            <string>男</string>
+           </property>
+           <property name="checked">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QRadioButton" name="radioButton_2">
+           <property name="text">
+            <string>女</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="checkBox">
+           <property name="text">
+            <string>中国</string>
+           </property>
+           <property name="checked">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="checkBox_2">
+           <property name="text">
+            <string>美国</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QComboBox" name="comboBox">
+           <item>
+            <property name="text">
+             <string>测试项目1</string>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>测试项目2</string>
+            </property>
+           </item>
+           <item>
+            <property name="text">
+             <string>测试项目3</string>
+            </property>
+           </item>
+          </widget>
+         </item>
+         <item>
+          <widget class="QDateEdit" name="dateEdit">
+           <property name="calendarPopup">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <widget class="QTabWidget" name="tabWidget">
+        <property name="currentIndex">
+         <number>0</number>
+        </property>
+        <widget class="QWidget" name="tab">
+         <attribute name="title">
+          <string>选项卡1</string>
+         </attribute>
+         <layout class="QVBoxLayout" name="verticalLayout_3">
+          <item>
+           <widget class="QTreeWidget" name="treeWidget">
+            <column>
+             <property name="text">
+              <string>学号</string>
+             </property>
+            </column>
+            <column>
+             <property name="text">
+              <string>成绩</string>
+             </property>
+            </column>
+            <item>
+             <property name="text">
+              <string>061104023</string>
+             </property>
+             <property name="text">
+              <string>105</string>
+             </property>
+            </item>
+            <item>
+             <property name="text">
+              <string>061104056</string>
+             </property>
+             <property name="text">
+              <string>245</string>
+             </property>
+            </item>
+            <item>
+             <property name="text">
+              <string>061104065</string>
+             </property>
+             <property name="text">
+              <string>265</string>
+             </property>
+            </item>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+        <widget class="QWidget" name="tab_2">
+         <attribute name="title">
+          <string>选项卡2</string>
+         </attribute>
+         <layout class="QVBoxLayout" name="verticalLayout_4">
+          <item>
+           <widget class="QTableWidget" name="tableWidget">
+            <property name="selectionBehavior">
+             <enum>QAbstractItemView::SelectRows</enum>
+            </property>
+            <row>
+             <property name="text">
+              <string>1</string>
+             </property>
+            </row>
+            <row>
+             <property name="text">
+              <string>2</string>
+             </property>
+            </row>
+            <row>
+             <property name="text">
+              <string>3</string>
+             </property>
+            </row>
+            <column>
+             <property name="text">
+              <string>学号</string>
+             </property>
+            </column>
+            <column>
+             <property name="text">
+              <string>成绩</string>
+             </property>
+            </column>
+            <item row="0" column="0">
+             <property name="text">
+              <string>061104023</string>
+             </property>
+            </item>
+            <item row="0" column="1">
+             <property name="text">
+              <string>105</string>
+             </property>
+            </item>
+            <item row="1" column="0">
+             <property name="text">
+              <string>061104025</string>
+             </property>
+            </item>
+            <item row="1" column="1">
+             <property name="text">
+              <string>108</string>
+             </property>
+            </item>
+            <item row="2" column="0">
+             <property name="text">
+              <string>061104056</string>
+             </property>
+            </item>
+            <item row="2" column="1">
+             <property name="text">
+              <string>235</string>
+             </property>
+            </item>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </widget>
+      </item>
+      <item>
+       <widget class="QProgressBar" name="progressBar">
+        <property name="value">
+         <number>24</number>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QSlider" name="horizontalSlider">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QScrollBar" name="horizontalScrollBar">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+</ui>

+ 77 - 0
src/CustomTitleWidget/frmmessagebox.cpp

@@ -0,0 +1,77 @@
+#include "frmmessagebox.h"
+#include "ui_frmmessagebox.h"
+#include "iconhelper.h"
+#include "myhelper.h"
+
+frmMessageBox::frmMessageBox(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::frmMessageBox)
+{
+    ui->setupUi(this);
+
+    this->mousePressed = false;
+    //设置窗体标题栏隐藏
+    this->setWindowFlags(Qt::FramelessWindowHint);
+    //设置窗体关闭时自动释放内存
+    this->setAttribute(Qt::WA_DeleteOnClose);
+    //设置图形字体
+    IconHelper::Instance()->SetIcon(ui->lab_Ico, QChar(0xf015), 12);
+    IconHelper::Instance()->SetIcon(ui->btnMenu_Close, QChar(0xf00d), 10);
+    //关联关闭按钮
+    connect(ui->btnMenu_Close, SIGNAL(clicked()), this, SLOT(close()));
+    connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(close()));
+    //窗体居中显示
+    myHelper::FormInCenter(this);
+
+}
+
+frmMessageBox::~frmMessageBox()
+{
+    delete ui;
+}
+
+void frmMessageBox::SetMessage(const QString &msg, int type)
+{
+    if (type == 0) {
+        ui->labIcoMain->setStyleSheet("border-image: url(:/image/info.png);");
+        ui->btnCancel->setVisible(false);
+        ui->lab_Title->setText("提示");
+    } else if (type == 1) {
+        ui->labIcoMain->setStyleSheet("border-image: url(:/image/question.png);");
+        ui->lab_Title->setText("询问");
+    } else if (type == 2) {
+        ui->labIcoMain->setStyleSheet("border-image: url(:/image/error.png);");
+        ui->btnCancel->setVisible(false);
+        ui->lab_Title->setText("错误");
+    }
+
+    ui->labInfo->setText(msg);
+}
+
+void frmMessageBox::on_btnOk_clicked()
+{
+    done(1);
+    this->close();
+}
+
+void frmMessageBox::mouseMoveEvent(QMouseEvent *e)
+{
+    if (mousePressed && (e->buttons() && Qt::LeftButton)) {
+        this->move(e->globalPos() - mousePoint);
+        e->accept();
+    }
+}
+
+void frmMessageBox::mousePressEvent(QMouseEvent *e)
+{
+    if (e->button() == Qt::LeftButton) {
+        mousePressed = true;
+        mousePoint = e->globalPos() - this->pos();
+        e->accept();
+    }
+}
+
+void frmMessageBox::mouseReleaseEvent(QMouseEvent *)
+{
+    mousePressed = false;
+}

+ 35 - 0
src/CustomTitleWidget/frmmessagebox.h

@@ -0,0 +1,35 @@
+#ifndef FRMMESSAGEBOX_H
+#define FRMMESSAGEBOX_H
+
+#include <QDialog>
+
+namespace Ui {
+class frmMessageBox;
+}
+
+class frmMessageBox : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit frmMessageBox(QWidget *parent = 0);
+    ~frmMessageBox();
+
+    void SetMessage(const QString &msg, int type);
+
+protected:
+    void mouseMoveEvent(QMouseEvent *e);
+    void mousePressEvent(QMouseEvent *e);
+    void mouseReleaseEvent(QMouseEvent *);
+
+private slots:
+    void on_btnOk_clicked();
+
+private:
+    Ui::frmMessageBox *ui;
+
+    QPoint mousePoint;              //鼠标拖动自定义标题栏时的坐标
+    bool mousePressed;              //鼠标是否按下
+};
+
+#endif // FRMMESSAGEBOX_H

+ 275 - 0
src/CustomTitleWidget/frmmessagebox.ui

@@ -0,0 +1,275 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>frmMessageBox</class>
+ <widget class="QDialog" name="frmMessageBox">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>303</width>
+    <height>143</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>提示</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widget_title" native="true">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>100</width>
+       <height>28</height>
+      </size>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="lab_Ico">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>31</width>
+          <height>0</height>
+         </size>
+        </property>
+        <property name="text">
+         <string/>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="lab_Title">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="styleSheet">
+         <string notr="true">font: 10pt &quot;微软雅黑&quot;;</string>
+        </property>
+        <property name="text">
+         <string>提示</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget_menu" native="true">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <property name="spacing">
+          <number>0</number>
+         </property>
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <widget class="QPushButton" name="btnMenu_Close">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="minimumSize">
+            <size>
+             <width>40</width>
+             <height>0</height>
+            </size>
+           </property>
+           <property name="cursor">
+            <cursorShape>ArrowCursor</cursorShape>
+           </property>
+           <property name="focusPolicy">
+            <enum>Qt::NoFocus</enum>
+           </property>
+           <property name="toolTip">
+            <string>关闭</string>
+           </property>
+           <property name="text">
+            <string/>
+           </property>
+           <property name="flat">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_main" native="true">
+     <property name="styleSheet">
+      <string notr="true">font: 11pt &quot;微软雅黑&quot;;</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>5</number>
+      </property>
+      <property name="margin">
+       <number>5</number>
+      </property>
+      <item>
+       <widget class="QGroupBox" name="groupBox">
+        <property name="title">
+         <string/>
+        </property>
+        <widget class="QLabel" name="labIcoMain">
+         <property name="geometry">
+          <rect>
+           <x>10</x>
+           <y>10</y>
+           <width>45</width>
+           <height>45</height>
+          </rect>
+         </property>
+         <property name="styleSheet">
+          <string notr="true">border-image: url(:/image/question.png);</string>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+        </widget>
+        <widget class="QLabel" name="labInfo">
+         <property name="geometry">
+          <rect>
+           <x>70</x>
+           <y>10</y>
+           <width>211</width>
+           <height>41</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>确定要删除吗?</string>
+         </property>
+         <property name="scaledContents">
+          <bool>false</bool>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+        </widget>
+        <widget class="QWidget" name="layoutWidget">
+         <property name="geometry">
+          <rect>
+           <x>10</x>
+           <y>60</y>
+           <width>271</width>
+           <height>34</height>
+          </rect>
+         </property>
+         <layout class="QHBoxLayout" name="horizontalLayout_3">
+          <item>
+           <spacer name="horizontalSpacer">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QPushButton" name="btnOk">
+            <property name="cursor">
+             <cursorShape>PointingHandCursor</cursorShape>
+            </property>
+            <property name="focusPolicy">
+             <enum>Qt::StrongFocus</enum>
+            </property>
+            <property name="styleSheet">
+             <string notr="true"/>
+            </property>
+            <property name="text">
+             <string>确定(&amp;O)</string>
+            </property>
+            <property name="icon">
+             <iconset>
+              <normaloff>:/image/update.png</normaloff>:/image/update.png</iconset>
+            </property>
+            <property name="iconSize">
+             <size>
+              <width>20</width>
+              <height>20</height>
+             </size>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QPushButton" name="btnCancel">
+            <property name="cursor">
+             <cursorShape>PointingHandCursor</cursorShape>
+            </property>
+            <property name="focusPolicy">
+             <enum>Qt::StrongFocus</enum>
+            </property>
+            <property name="styleSheet">
+             <string notr="true"/>
+            </property>
+            <property name="text">
+             <string>取消(&amp;C)</string>
+            </property>
+            <property name="icon">
+             <iconset>
+              <normaloff>:/image/close.png</normaloff>:/image/close.png</iconset>
+            </property>
+            <property name="iconSize">
+             <size>
+              <width>20</width>
+              <height>20</height>
+             </size>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 24 - 0
src/CustomTitleWidget/iconhelper.cpp

@@ -0,0 +1,24 @@
+#include "iconhelper.h"
+
+IconHelper* IconHelper::_instance = 0;
+IconHelper::IconHelper(QObject*):
+    QObject(qApp)
+{
+    int fontId = QFontDatabase::addApplicationFont(":/image/fontawesome-webfont.ttf");
+    QString fontName = QFontDatabase::applicationFontFamilies(fontId).at(0);
+    iconFont = QFont(fontName);
+}
+
+void IconHelper::SetIcon(QLabel* lab, QChar c, int size)
+{
+    iconFont.setPointSize(size);
+    lab->setFont(iconFont);
+    lab->setText(c);
+}
+
+void IconHelper::SetIcon(QPushButton* btn, QChar c, int size)
+{
+    iconFont.setPointSize(size);
+    btn->setFont(iconFont);
+    btn->setText(c);
+}

+ 37 - 0
src/CustomTitleWidget/iconhelper.h

@@ -0,0 +1,37 @@
+#ifndef ICONHELPER_H
+#define ICONHELPER_H
+
+#include <QObject>
+#include <QFont>
+#include <QFontDatabase>
+#include <QMutex>
+#include <QLabel>
+#include <QPushButton>
+#include <QApplication>
+
+class IconHelper : public QObject
+{
+private:
+    explicit IconHelper(QObject *parent = 0);
+    QFont iconFont;
+    static IconHelper* _instance;
+
+public:
+    static IconHelper* Instance()
+    {
+        static QMutex mutex;
+        if (!_instance) {
+            QMutexLocker locker(&mutex);
+            if (!_instance) {
+                _instance = new IconHelper;
+            }
+        }
+        return _instance;
+    }
+
+    void SetIcon(QLabel* lab, QChar c, int size = 10);
+    void SetIcon(QPushButton* btn, QChar c, int size = 10);
+
+};
+
+#endif // ICONHELPER_H

二進制
src/CustomTitleWidget/image/add-line_horizontal.png


二進制
src/CustomTitleWidget/image/add-line_vertical.png


二進制
src/CustomTitleWidget/image/array_down.png


+ 354 - 0
src/CustomTitleWidget/image/black.css

@@ -0,0 +1,354 @@
+QWidget#frmLogin,QWidget#frmPopup,QWidget#frmHostInfo,QWidget#frmLogout,QWidget#frmConfig,QWidget#frmData,QWidget#frmDefence,QWidget#frmHost,QWidget#frmMain,QWidget#CustomTitle,QWidget#frmPwd,QWidget#frmSelect,QWidget#frmMessageBox{
+	border:1px solid #4D4D4D;
+	border-radius:0px;	
+}
+
+.QFrame{
+	border:1px solid #636363;
+	border-radius:5px;
+}
+/*
+QWidget#widget_title{
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #4D4D4D, stop:1 #292929);
+}*/
+
+QWidget#widget_title{
+        background-color:rgb(60, 65, 68);
+}
+
+QLabel#lab_Ico,QLabel#lab_Title{
+	border-radius:0px;
+	color: #F0F0F0;
+	background-color:rgba(0,0,0,0);
+	border-style:none;
+}
+/*
+QLineEdit {
+	border: 1px solid #636363;
+	border-radius: 5px;
+	padding: 2px;
+	background: none;
+	selection-background-color: #4D4D4D;
+}
+
+QLineEdit[echoMode="2"] { 
+	lineedit-password-character: 9679; 
+}*/
+
+.QGroupBox{
+	border: 1px solid #636363;
+	border-radius: 5px;
+}
+
+/*
+.QPushButton{
+	border-style: none;
+	border: 0px;
+	color: #F0F0F0;
+	padding: 5px;	
+	min-height: 20px;
+	border-radius:5px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #4D4D4D, stop:1 #292929); 
+}
+
+.QPushButton[focusPolicy="0"] {
+	border-style: none;
+	border: 0px;
+	color: #F0F0F0;
+	padding: 0px;	
+	min-height: 10px;
+	border-radius:3px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #4D4D4D, stop:1 #292929); 
+}
+
+.QPushButton:hover{ 
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #636363, stop:1 #575757);
+}
+
+.QPushButton:pressed{ 
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #4D4D4D, stop:1 #292929);
+}
+*/
+
+QPushButton#btnMenu,QPushButton#btnMenu_Min,QPushButton#btnMenu_Max,QPushButton#btnMenu_Close{
+	border-radius:0px;
+	color: #F0F0F0;
+	background-color:rgba(0,0,0,0);
+	border-style:none;
+}
+
+QPushButton#btnMenu:hover,QPushButton#btnMenu_Min:hover,QPushButton#btnMenu_Max:hover{
+	background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(25, 134, 199, 0), stop:1 #636363);
+}
+
+QPushButton#btnMenu_Close:hover{
+	background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(238, 0, 0, 128), stop:1 rgba(238, 44, 44, 255));
+}
+
+QCheckBox {
+	spacing: 2px; 
+}
+
+QCheckBox::indicator {
+	width: 20px;
+	height: 20px;
+}
+
+QCheckBox::indicator:unchecked {
+	image: url(:/image/checkbox_unchecked.png);
+}
+
+QCheckBox::indicator:checked {
+	image: url(:/image/checkbox_checked.png); 
+}
+
+QRadioButton {
+	spacing: 2px;
+}
+
+QRadioButton::indicator {
+	width: 15px; 
+	height: 15px; 
+}
+
+QRadioButton::indicator::unchecked {
+	image: url(:/image/radio_normal.png); 
+}
+
+QRadioButton::indicator::checked {
+	image: url(:/image/radio_selected.png); 
+}
+/*
+QComboBox,QDateEdit{
+	border-radius: 3px;
+	padding: 1px 10px 1px 5px;
+	border: 1px solid #636363;
+}
+
+QComboBox::drop-down,QDateEdit::drop-down {
+	subcontrol-origin: padding;
+	subcontrol-position: top right;
+	width: 15px; 
+	border-left-width: 1px;
+	border-left-style: solid;
+	border-top-right-radius: 3px;
+	border-bottom-right-radius: 3px;
+	border-left-color: #636363;
+}
+
+QComboBox::down-arrow,QDateEdit::down-arrow {
+	image: url(:/image/array_down.png); 
+}
+*/
+QMenu {
+	background-color:#F0F0F0;
+	margin: 2px;
+}
+
+QMenu::item {	
+	padding: 2px 12px 2px 12px;
+}
+
+QMenu::indicator {
+	width: 13px;
+	height: 13px;
+}
+
+QMenu::item:selected {
+	color: #F0F0F0;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #4D4D4D, stop:1 #292929); 
+}
+
+QMenu::separator {
+	height: 1px;
+	background: #636363;
+}
+
+QProgressBar {
+	border-radius: 5px;
+	text-align: center;
+	border: 1px solid #636363;
+}
+
+QProgressBar::chunk {
+	width: 5px; 
+	margin: 0.5px;
+	background-color: #4D4D4D;
+}
+
+QSlider::groove:horizontal,QSlider::add-page:horizontal { 
+	background: #808080; 
+	height: 8px; 
+	border-radius: 3px; 
+}
+
+QSlider::sub-page:horizontal {
+	height: 8px; 
+	border-radius: 3px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #4D4D4D, stop:1 #292929); 
+}
+
+QSlider::handle:horizontal {
+	width: 13px; 
+	margin-top: -3px; 
+	margin-bottom: -3px; 
+	border-radius: 6px;
+	background: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5,stop:0.6 #F0F0F0, stop:0.778409 #636363);
+}
+
+QSlider::handle:horizontal:hover {
+	background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #F0F0F0,stop:0.778409 #4D4D4D);
+}
+
+QSlider::groove:vertical,QSlider::sub-page:vertical {
+	background:#808080; 
+	width: 8px; 
+	border-radius: 3px;
+}
+
+QSlider::add-page:vertical {
+	width: 8px;
+	border-radius: 3px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #4D4D4D, stop:1 #292929); 
+}
+
+QSlider::handle:vertical {
+	height: 14px; 
+	margin-left: -3px;
+	margin-right: -3px;
+	border-radius: 6px;
+	background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #F0F0F0, stop:0.778409 #636363);
+}
+
+QSlider::handle:vertical:hover {
+	background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #F0F0F0,stop:0.778409 #4D4D4D);
+}
+
+QScrollBar:vertical {
+	width:10px; 
+	background-color:rgba(0,0,0,0%); 
+	padding-top:10px; 
+	padding-bottom:10px;
+}
+
+QScrollBar:horizontal {
+	height:10px; 
+	background-color:rgba(0,0,0,0%); 
+	padding-left:10px; padding-right:10px;
+}
+
+QScrollBar::handle:vertical {
+	width:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #636363, stop:1 #575757); 
+}
+
+QScrollBar::handle:horizontal {
+	height:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #636363, stop:1 #575757); 
+}
+
+QScrollBar::handle:vertical:hover {
+	width:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #4D4D4D, stop:1 #292929); 
+}
+
+QScrollBar::handle:horizontal:hover {
+	height:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #4D4D4D, stop:1 #292929); 
+}
+
+QScrollBar::add-line:vertical {
+	height:10px;
+	width:10px;
+	subcontrol-position: bottom; 
+	subcontrol-origin: margin;
+	border-image:url(:/image/add-line_vertical.png);
+}
+
+QScrollBar::add-line:horizontal {
+	height:10px;
+	width:10px;
+	subcontrol-position: right;
+	subcontrol-origin: margin;
+	border-image:url(:/image/add-line_horizontal.png);
+}
+
+QScrollBar::sub-line:vertical {
+	height:10px;
+	width:10px;
+	subcontrol-position: top; 
+	subcontrol-origin: margin;
+	border-image:url(:/image/sub-line_vertical.png);
+}
+
+QScrollBar::sub-line:horizontal {
+	height:10px;
+	width:10px;
+	subcontrol-position: left;
+	subcontrol-origin: margin;
+	border-image:url(:/image/sub-line_horizontal.png);
+}
+
+QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical {
+	width:10px;
+	background: #C0C0C0;
+}
+
+QScrollBar::add-page:horizontal,QScrollBar::sub-page:horizontal {
+	height:10px;
+	background: #C0C0C0;
+}
+
+QScrollArea {
+	border: 0px ; 
+}
+
+/*
+QTreeView,QListView,QTableView{
+	border: 1px solid #636363; 
+	selection-background-color: #4D4D4D;
+	selection-color: #F0F0F0;
+}*/
+
+QTableView::item:selected, QListView::item:selected, QTreeView::item:selected {
+	color: #F0F0F0;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #4D4D4D, stop:1 #292929); 
+}
+
+QTableView::item:hover, QListView::item:hover, QTreeView::item:hover {
+	color: #F0F0F0;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #636363, stop:1 #575757); 
+}
+
+QTableView::item, QListView::item, QTreeView::item {
+	padding: 5px; 
+	margin: 0px; 
+}
+
+QHeaderView::section {
+	padding:3px;
+	margin:0px;
+	color:#F0F0F0;
+	border: 1px solid #F0F0F0;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #636363, stop:1 #575757);
+}
+
+QTabBar::tab {
+	border-bottom-left-radius:0px;
+	border-bottom-right-radius:0px;
+	color: #F0F0F0;
+	min-width: 60px;
+	min-height: 20px;
+	padding: 3px 8px 3px 8px;
+	margin:1px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #636363, stop:1 #575757); 
+}
+
+QTabBar::tab:selected, QTabBar::tab:hover {
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #4D4D4D, stop:1 #292929); 
+}
+
+QStatusBar::item {
+     border: 1px solid #636363;
+     border-radius: 3px;
+}

+ 350 - 0
src/CustomTitleWidget/image/blue.css

@@ -0,0 +1,350 @@
+QWidget#frmLogin,QWidget#frmPopup,QWidget#frmHostInfo,QWidget#frmLogout,QWidget#frmConfig,QWidget#frmData,QWidget#frmDefence,QWidget#frmHost,QWidget#frmMain,QWidget#frmPwd,QWidget#frmSelect,QWidget#frmMessageBox{
+	border:1px solid #1B89CA;
+	border-radius:0px;	
+}
+
+.QFrame{
+	border:1px solid #5CACEE;
+	border-radius:5px;
+}
+
+QWidget#widget_title{
+/*	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #1B89CA, stop:1 #1077B5);*/
+    background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgb(26,171,218), stop:1 rgb(41,174,218));
+}
+
+QLabel#lab_Ico,QLabel#lab_Title{
+	border-radius:0px;
+	color: #F0F0F0;
+	background-color:rgba(0,0,0,0);
+	border-style:none;
+}
+
+QLineEdit {
+	border: 1px solid #5CACEE;
+        border-radius: 2px;
+	padding: 2px;
+	background: none;
+	selection-background-color: #1B89CA;
+}
+
+QLineEdit[echoMode="2"] { 
+	lineedit-password-character: 9679; 
+}
+
+.QGroupBox{
+	border: 1px solid #5CACEE;
+	border-radius: 5px;
+}
+
+.QPushButton{
+        border-style: none;
+        border: 0px;
+        color: #F0F0F0;
+/*	padding: 5px;	*/
+/*        min-height: 20px;*/
+        border-radius:5px;
+        background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #1B89CA, stop:1 #1077B5);
+}
+
+.QPushButton[focusPolicy="0"] {
+	border-style: none;
+	border: 0px;
+	color: #F0F0F0;
+	padding: 0px;	
+	min-height: 10px;
+	border-radius:3px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #1B89CA, stop:1 #1077B5); 
+}
+
+.QPushButton:hover{ 
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #5CACEE, stop:1 #4F94CD);
+}
+
+.QPushButton:pressed{
+        background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #1B89CA, stop:1 #1077B5);
+}
+
+QPushButton#btnMenu,QPushButton#btnMenu_Min,QPushButton#btnMenu_Max,QPushButton#btnMenu_Close{
+	border-radius:0px;
+	color: #F0F0F0;
+	background-color:rgba(0,0,0,0);
+	border-style:none;
+}
+
+QPushButton#btnMenu:hover,QPushButton#btnMenu_Min:hover,QPushButton#btnMenu_Max:hover{
+	background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(25, 134, 199, 0), stop:1 #5CACEE);
+}
+
+QPushButton#btnMenu_Close:hover{
+	background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(238, 0, 0, 128), stop:1 rgba(238, 44, 44, 255));
+}
+
+QCheckBox {
+	spacing: 2px; 
+}
+
+QCheckBox::indicator {
+	width: 20px;
+	height: 20px;
+}
+
+QCheckBox::indicator:unchecked {
+	image: url(:/image/checkbox_unchecked.png);
+}
+
+QCheckBox::indicator:checked {
+	image: url(:/image/checkbox_checked.png); 
+}
+
+QRadioButton {
+	spacing: 2px;
+}
+
+QRadioButton::indicator {
+	width: 15px; 
+	height: 15px; 
+}
+
+QRadioButton::indicator::unchecked {
+	image: url(:/image/radio_normal.png); 
+}
+
+QRadioButton::indicator::checked {
+	image: url(:/image/radio_selected.png); 
+}
+
+QComboBox,QDateEdit{
+	border-radius: 3px;
+	padding: 1px 10px 1px 5px;
+	border: 1px solid #5CACEE;
+}
+
+QComboBox::drop-down,QDateEdit::drop-down {
+	subcontrol-origin: padding;
+	subcontrol-position: top right;
+	width: 15px; 
+	border-left-width: 1px;
+	border-left-style: solid;
+	border-top-right-radius: 3px;
+	border-bottom-right-radius: 3px;
+	border-left-color: #5CACEE;
+}
+
+QComboBox::down-arrow,QDateEdit::down-arrow {
+	image: url(:/image/array_down.png); 
+}
+
+/*QMenu {
+	background-color:#F0F0F0;
+	margin: 2px;
+}
+
+QMenu::item {	
+	padding: 2px 12px 2px 12px;
+}
+
+QMenu::indicator {
+	width: 13px;
+	height: 13px;
+}
+
+QMenu::item:selected {
+	color: #FFFFFF;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #1B89CA, stop:1 #1077B5); 
+}
+
+QMenu::separator {
+	height: 1px;
+	background: #5CACEE;
+}*/
+
+QProgressBar {
+	border-radius: 5px;
+	text-align: center;
+	border: 1px solid #5CACEE;
+}
+
+QProgressBar::chunk {
+	width: 5px; 
+	margin: 0.5px;
+	background-color: #1B89CA;
+}
+
+QSlider::groove:horizontal,QSlider::add-page:horizontal { 
+	background: #808080; 
+	height: 8px; 
+	border-radius: 3px; 
+}
+
+QSlider::sub-page:horizontal {
+	height: 8px; 
+	border-radius: 3px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #1B89CA, stop:1 #1077B5); 
+}
+
+QSlider::handle:horizontal {
+	width: 13px; 
+	margin-top: -3px; 
+	margin-bottom: -3px; 
+	border-radius: 6px;
+	background: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5,stop:0.6 #F0F0F0, stop:0.778409 #5CACEE);
+}
+
+QSlider::handle:horizontal:hover {
+	background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #F0F0F0,stop:0.778409 #1B89CA);
+}
+
+QSlider::groove:vertical,QSlider::sub-page:vertical {
+	background:#808080; 
+	width: 8px; 
+	border-radius: 3px;
+}
+
+QSlider::add-page:vertical {
+	width: 8px;
+	border-radius: 3px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #1B89CA, stop:1 #1077B5); 
+}
+
+QSlider::handle:vertical {
+	height: 14px; 
+	margin-left: -3px;
+	margin-right: -3px;
+	border-radius: 6px;
+	background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #F0F0F0, stop:0.778409 #5CACEE);
+}
+
+QSlider::handle:vertical:hover {
+	background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #F0F0F0,stop:0.778409 #1B89CA);
+}
+
+QScrollBar:vertical {
+	width:10px; 
+	background-color:rgba(0,0,0,0%); 
+	padding-top:10px; 
+	padding-bottom:10px;
+}
+
+QScrollBar:horizontal {
+	height:10px; 
+	background-color:rgba(0,0,0,0%); 
+	padding-left:10px; padding-right:10px;
+}
+
+QScrollBar::handle:vertical {
+	width:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #5CACEE, stop:1 #4F94CD); 
+}
+
+QScrollBar::handle:horizontal {
+	height:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #5CACEE, stop:1 #4F94CD); 
+}
+
+QScrollBar::handle:vertical:hover {
+	width:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #1B89CA, stop:1 #1077B5); 
+}
+
+QScrollBar::handle:horizontal:hover {
+	height:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #1B89CA, stop:1 #1077B5); 
+}
+
+QScrollBar::add-line:vertical {
+	height:10px;
+	width:10px;
+	subcontrol-position: bottom; 
+	subcontrol-origin: margin;
+	border-image:url(:/image/add-line_vertical.png);
+}
+
+QScrollBar::add-line:horizontal {
+	height:10px;
+	width:10px;
+	subcontrol-position: right;
+	subcontrol-origin: margin;
+	border-image:url(:/image/add-line_horizontal.png);
+}
+
+QScrollBar::sub-line:vertical {
+	height:10px;
+	width:10px;
+	subcontrol-position: top; 
+	subcontrol-origin: margin;
+	border-image:url(:/image/sub-line_vertical.png);
+}
+
+QScrollBar::sub-line:horizontal {
+	height:10px;
+	width:10px;
+	subcontrol-position: left;
+	subcontrol-origin: margin;
+	border-image:url(:/image/sub-line_horizontal.png);
+}
+
+QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical {
+	width:10px;
+	background: #C0C0C0;
+}
+
+QScrollBar::add-page:horizontal,QScrollBar::sub-page:horizontal {
+	height:10px;
+	background: #C0C0C0;
+}
+
+QScrollArea {
+	border: 0px ; 
+}
+
+QTreeView,QListView,QTableView{
+	border: 1px solid #5CACEE; 
+	selection-background-color: #1B89CA;
+	selection-color: #F0F0F0;
+}
+
+QTableView::item:selected, QListView::item:selected, QTreeView::item:selected {
+/*	color: #F0F0F0;*/
+        background-color: rgb(219,240,255);
+        background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #1B89CA, stop:1 #1077B5);
+}
+
+QTableView::item:hover, QListView::item:hover, QTreeView::item:hover {
+/*	color: #F0F0F0;*/
+        background-color: rgb(240,249,255);
+        background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #5CACEE, stop:1 #4F94CD);
+}
+
+QTableView::item, QListView::item, QTreeView::item {
+/*	padding: 5px; */
+	margin: 0px; 
+}
+
+QHeaderView::section {
+	padding:3px;
+	margin:0px;
+	color:#F0F0F0;
+	border: 1px solid #F0F0F0;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #5CACEE, stop:1 #4F94CD);
+}
+
+QTabBar::tab {
+	border-bottom-left-radius:0px;
+	border-bottom-right-radius:0px;
+	color: #F0F0F0;
+	min-width: 60px;
+	min-height: 20px;
+	padding: 3px 8px 3px 8px;
+	margin:1px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #5CACEE, stop:1 #4F94CD); 
+}
+
+QTabBar::tab:selected, QTabBar::tab:hover {
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #1B89CA, stop:1 #1077B5); 
+}
+
+QStatusBar::item {
+     border: 1px solid #5CACEE;
+     border-radius: 3px;
+}

二進制
src/CustomTitleWidget/image/checkbox_checked.png


二進制
src/CustomTitleWidget/image/checkbox_unchecked.png


二進制
src/CustomTitleWidget/image/error.png


二進制
src/CustomTitleWidget/image/fontawesome-webfont.ttf


+ 353 - 0
src/CustomTitleWidget/image/gray.css

@@ -0,0 +1,353 @@
+QWidget#frmLogin,QWidget#frmPopup,QWidget#frmHostInfo,QWidget#frmLogout,QWidget#frmConfig,QWidget#frmData,QWidget#frmDefence,QWidget#frmHost,QWidget#frmMain,QWidget#frmPwd,QWidget#frmSelect,QWidget#frmMessageBox{
+	border:1px solid #454648;
+	border-radius:0px;	
+}
+
+.QFrame{
+	border:1px solid #B8B8B8;
+	border-radius:5px;
+}
+
+QWidget#widget_title{
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #454648, stop:1 #7A7A7A);
+}
+
+QWidget#widget_back{
+        background-color: rgb(22, 22, 22);
+        border:1px solid rgba(0, 0, 0, 30);
+        border-radius:2px;
+}
+
+QLabel#lab_Ico,QLabel#lab_Title{
+	border-radius:0px;
+	color: #F0F0F0;
+	background-color:rgba(0,0,0,0);
+	border-style:none;
+}
+
+QLineEdit {
+	border: 1px solid #B8B8B8;
+	border-radius: 5px;
+	padding: 2px;
+	background: none;
+	selection-background-color: #454648;
+}
+
+QLineEdit[echoMode="2"] { 
+	lineedit-password-character: 9679; 
+}
+
+.QGroupBox{
+	border: 1px solid #B8B8B8;
+	border-radius: 5px;
+}
+/*
+.QPushButton{
+	border-style: none;
+	border: 0px;
+	color: #F0F0F0;
+	padding: 5px;	
+	min-height: 20px;
+	border-radius:5px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #454648, stop:1 #7A7A7A); 
+}
+
+.QPushButton[focusPolicy="0"] {
+	border-style: none;
+	border: 0px;
+	color: #F0F0F0;
+	padding: 0px;	
+	min-height: 10px;
+	border-radius:3px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #454648, stop:1 #7A7A7A); 
+}
+
+.QPushButton:hover{ 
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #B8B8B8, stop:1 #D6D6D6);
+}
+
+.QPushButton:pressed{ 
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #454648, stop:1 #7A7A7A);
+}*/
+
+QPushButton#btnMenu,QPushButton#btnMenu_Min,QPushButton#btnMenu_Max,QPushButton#btnMenu_Close{
+	border-radius:0px;
+	color: #F0F0F0;
+	background-color:rgba(0,0,0,0);
+	border-style:none;
+}
+
+QPushButton#btnMenu:hover,QPushButton#btnMenu_Min:hover,QPushButton#btnMenu_Max:hover{
+	background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(25, 134, 199, 0), stop:1 #B8B8B8);
+}
+
+QPushButton#btnMenu_Close:hover{
+	background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(238, 0, 0, 128), stop:1 rgba(238, 44, 44, 255));
+}
+
+QCheckBox {
+	spacing: 2px; 
+}
+
+QCheckBox::indicator {
+	width: 20px;
+	height: 20px;
+}
+
+QCheckBox::indicator:unchecked {
+	image: url(:/image/checkbox_unchecked.png);
+}
+
+QCheckBox::indicator:checked {
+	image: url(:/image/checkbox_checked.png); 
+}
+
+QRadioButton {
+	spacing: 2px;
+}
+
+QRadioButton::indicator {
+	width: 15px; 
+	height: 15px; 
+}
+
+QRadioButton::indicator::unchecked {
+	image: url(:/image/radio_normal.png); 
+}
+
+QRadioButton::indicator::checked {
+	image: url(:/image/radio_selected.png); 
+}
+
+QComboBox,QDateEdit{
+	border-radius: 3px;
+	padding: 1px 10px 1px 5px;
+	border: 1px solid #B8B8B8;
+}
+
+QComboBox::drop-down,QDateEdit::drop-down {
+	subcontrol-origin: padding;
+	subcontrol-position: top right;
+	width: 15px; 
+	border-left-width: 1px;
+	border-left-style: solid;
+	border-top-right-radius: 3px;
+	border-bottom-right-radius: 3px;
+	border-left-color: #B8B8B8;
+}
+
+QComboBox::down-arrow,QDateEdit::down-arrow {
+	image: url(:/image/array_down.png); 
+}
+
+QMenu {
+	background-color:#F0F0F0;
+	margin: 2px;
+}
+
+QMenu::item {	
+	padding: 2px 12px 2px 12px;
+}
+
+QMenu::indicator {
+	width: 13px;
+	height: 13px;
+}
+
+QMenu::item:selected {
+	color: #F0F0F0;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #454648, stop:1 #7A7A7A); 
+}
+
+QMenu::separator {
+	height: 1px;
+	background: #B8B8B8;
+}
+
+QProgressBar {
+	border-radius: 5px;
+	text-align: center;
+	border: 1px solid #B8B8B8;
+}
+
+QProgressBar::chunk {
+	width: 5px; 
+	margin: 0.5px;
+	background-color: #454648;
+}
+
+QSlider::groove:horizontal,QSlider::add-page:horizontal { 
+	background: #808080; 
+	height: 8px; 
+	border-radius: 3px; 
+}
+
+QSlider::sub-page:horizontal {
+	height: 8px; 
+	border-radius: 3px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #454648, stop:1 #7A7A7A); 
+}
+
+QSlider::handle:horizontal {
+	width: 13px; 
+	margin-top: -3px; 
+	margin-bottom: -3px; 
+	border-radius: 6px;
+	background: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5,stop:0.6 #F0F0F0, stop:0.778409 #B8B8B8);
+}
+
+QSlider::handle:horizontal:hover {
+	background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #F0F0F0,stop:0.778409 #454648);
+}
+
+QSlider::groove:vertical,QSlider::sub-page:vertical {
+	background:#808080; 
+	width: 8px; 
+	border-radius: 3px;
+}
+
+QSlider::add-page:vertical {
+	width: 8px;
+	border-radius: 3px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #454648, stop:1 #7A7A7A); 
+}
+
+QSlider::handle:vertical {
+	height: 14px; 
+	margin-left: -3px;
+	margin-right: -3px;
+	border-radius: 6px;
+	background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #F0F0F0, stop:0.778409 #B8B8B8);
+}
+
+QSlider::handle:vertical:hover {
+	background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #F0F0F0,stop:0.778409 #454648);
+}
+
+QScrollBar:vertical {
+	width:10px; 
+	background-color:rgba(0,0,0,0%); 
+	padding-top:10px; 
+	padding-bottom:10px;
+}
+
+QScrollBar:horizontal {
+	height:10px; 
+	background-color:rgba(0,0,0,0%); 
+	padding-left:10px; padding-right:10px;
+}
+
+QScrollBar::handle:vertical {
+	width:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #B8B8B8, stop:1 #D6D6D6); 
+}
+
+QScrollBar::handle:horizontal {
+	height:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #B8B8B8, stop:1 #D6D6D6); 
+}
+
+QScrollBar::handle:vertical:hover {
+	width:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #454648, stop:1 #7A7A7A); 
+}
+
+QScrollBar::handle:horizontal:hover {
+	height:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #454648, stop:1 #7A7A7A); 
+}
+
+QScrollBar::add-line:vertical {
+	height:10px;
+	width:10px;
+	subcontrol-position: bottom; 
+	subcontrol-origin: margin;
+	border-image:url(:/image/add-line_vertical.png);
+}
+
+QScrollBar::add-line:horizontal {
+	height:10px;
+	width:10px;
+	subcontrol-position: right;
+	subcontrol-origin: margin;
+	border-image:url(:/image/add-line_horizontal.png);
+}
+
+QScrollBar::sub-line:vertical {
+	height:10px;
+	width:10px;
+	subcontrol-position: top; 
+	subcontrol-origin: margin;
+	border-image:url(:/image/sub-line_vertical.png);
+}
+
+QScrollBar::sub-line:horizontal {
+	height:10px;
+	width:10px;
+	subcontrol-position: left;
+	subcontrol-origin: margin;
+	border-image:url(:/image/sub-line_horizontal.png);
+}
+
+QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical {
+	width:10px;
+	background: #C0C0C0;
+}
+
+QScrollBar::add-page:horizontal,QScrollBar::sub-page:horizontal {
+	height:10px;
+	background: #C0C0C0;
+}
+
+QScrollArea {
+	border: 0px ; 
+}
+
+QTreeView,QListView,QTableView{
+	border: 1px solid #B8B8B8; 
+	selection-background-color: #454648;
+	selection-color: #F0F0F0;
+}
+
+QTableView::item:selected, QListView::item:selected, QTreeView::item:selected {
+	color: #F0F0F0;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #454648, stop:1 #7A7A7A); 
+}
+
+QTableView::item:hover, QListView::item:hover, QTreeView::item:hover {
+	color: #F0F0F0;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #B8B8B8, stop:1 #D6D6D6); 
+}
+
+QTableView::item, QListView::item, QTreeView::item {
+	padding: 5px; 
+	margin: 0px; 
+}
+
+QHeaderView::section {
+	padding:3px;
+	margin:0px;
+	color:#F0F0F0;
+	border: 1px solid #F0F0F0;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #B8B8B8, stop:1 #D6D6D6);
+}
+
+QTabBar::tab {
+	border-bottom-left-radius:0px;
+	border-bottom-right-radius:0px;
+	color: #F0F0F0;
+	min-width: 60px;
+	min-height: 20px;
+	padding: 3px 8px 3px 8px;
+	margin:1px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #B8B8B8, stop:1 #D6D6D6); 
+}
+
+QTabBar::tab:selected, QTabBar::tab:hover {
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #454648, stop:1 #7A7A7A); 
+}
+
+QStatusBar::item {
+     border: 1px solid #B8B8B8;
+     border-radius: 3px;
+}

二進制
src/CustomTitleWidget/image/info.png


+ 347 - 0
src/CustomTitleWidget/image/navy.css

@@ -0,0 +1,347 @@
+QWidget#frmLogin,QWidget#frmPopup,QWidget#frmHostInfo,QWidget#frmLogout,QWidget#frmConfig,QWidget#frmData,QWidget#frmDefence,QWidget#frmHost,QWidget#frmMain,QWidget#frmPwd,QWidget#frmSelect,QWidget#frmMessageBox{
+	border:1px solid #0F7DBE;
+	border-radius:0px;	
+}
+
+.QFrame{
+	border:1px solid #50A3F0;
+	border-radius:5px;
+}
+
+QWidget#widget_title{
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #0F7DBE, stop:1 #1582C3);
+}
+
+QLabel#lab_Ico,QLabel#lab_Title{
+	border-radius:0px;
+	color: #F0F0F0;
+	background-color:rgba(0,0,0,0);
+	border-style:none;
+}
+
+QLineEdit {
+	border: 1px solid #50A3F0;
+	border-radius: 5px;
+	padding: 2px;
+	background: none;
+	selection-background-color: #0F7DBE;
+}
+
+QLineEdit[echoMode="2"] { 
+	lineedit-password-character: 9679; 
+}
+
+.QGroupBox{
+	border: 1px solid #50A3F0;
+	border-radius: 5px;
+}
+
+.QPushButton{
+	border-style: none;
+	border: 0px;
+	color: #F0F0F0;
+	padding: 5px;	
+	min-height: 20px;
+	border-radius:5px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #0F7DBE, stop:1 #1582C3); 
+}
+
+.QPushButton[focusPolicy="0"] {
+	border-style: none;
+	border: 0px;
+	color: #F0F0F0;
+	padding: 0px;	
+	min-height: 10px;
+	border-radius:3px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #0F7DBE, stop:1 #1582C3); 
+}
+
+.QPushButton:hover{ 
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #50A3F0, stop:1 #489CEA);
+}
+
+.QPushButton:pressed{ 
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #0F7DBE, stop:1 #1582C3);
+}
+
+QPushButton#btnMenu,QPushButton#btnMenu_Min,QPushButton#btnMenu_Max,QPushButton#btnMenu_Close{
+	border-radius:0px;
+	color: #F0F0F0;
+	background-color:rgba(0,0,0,0);
+	border-style:none;
+}
+
+QPushButton#btnMenu:hover,QPushButton#btnMenu_Min:hover,QPushButton#btnMenu_Max:hover{
+	background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(25, 134, 199, 0), stop:1 #50A3F0);
+}
+
+QPushButton#btnMenu_Close:hover{
+	background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(238, 0, 0, 128), stop:1 rgba(238, 44, 44, 255));
+}
+
+QCheckBox {
+	spacing: 2px; 
+}
+
+QCheckBox::indicator {
+	width: 20px;
+	height: 20px;
+}
+
+QCheckBox::indicator:unchecked {
+	image: url(:/image/checkbox_unchecked.png);
+}
+
+QCheckBox::indicator:checked {
+	image: url(:/image/checkbox_checked.png); 
+}
+
+QRadioButton {
+	spacing: 2px;
+}
+
+QRadioButton::indicator {
+	width: 15px; 
+	height: 15px; 
+}
+
+QRadioButton::indicator::unchecked {
+	image: url(:/image/radio_normal.png); 
+}
+
+QRadioButton::indicator::checked {
+	image: url(:/image/radio_selected.png); 
+}
+
+QComboBox,QDateEdit{
+	border-radius: 3px;
+	padding: 1px 10px 1px 5px;
+	border: 1px solid #50A3F0;
+}
+
+QComboBox::drop-down,QDateEdit::drop-down {
+	subcontrol-origin: padding;
+	subcontrol-position: top right;
+	width: 15px; 
+	border-left-width: 1px;
+	border-left-style: solid;
+	border-top-right-radius: 3px;
+	border-bottom-right-radius: 3px;
+	border-left-color: #50A3F0;
+}
+
+QComboBox::down-arrow,QDateEdit::down-arrow {
+	image: url(:/image/array_down.png); 
+}
+
+QMenu {
+	background-color:#F0F0F0;
+	margin: 2px;
+}
+
+QMenu::item {	
+	padding: 2px 12px 2px 12px;
+}
+
+QMenu::indicator {
+	width: 13px;
+	height: 13px;
+}
+
+QMenu::item:selected {
+	color: #F0F0F0;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #0F7DBE, stop:1 #1582C3); 
+}
+
+QMenu::separator {
+	height: 1px;
+	background: #50A3F0;
+}
+
+QProgressBar {
+	border-radius: 5px;
+	text-align: center;
+	border: 1px solid #50A3F0;
+}
+
+QProgressBar::chunk {
+	width: 5px; 
+	margin: 0.5px;
+	background-color: #0F7DBE;
+}
+
+QSlider::groove:horizontal,QSlider::add-page:horizontal { 
+	background: #808080; 
+	height: 8px; 
+	border-radius: 3px; 
+}
+
+QSlider::sub-page:horizontal {
+	height: 8px; 
+	border-radius: 3px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #0F7DBE, stop:1 #1582C3); 
+}
+
+QSlider::handle:horizontal {
+	width: 13px; 
+	margin-top: -3px; 
+	margin-bottom: -3px; 
+	border-radius: 6px;
+	background: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5,stop:0.6 #F0F0F0, stop:0.778409 #50A3F0);
+}
+
+QSlider::handle:horizontal:hover {
+	background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #F0F0F0,stop:0.778409 #0F7DBE);
+}
+
+QSlider::groove:vertical,QSlider::sub-page:vertical {
+	background:#808080; 
+	width: 8px; 
+	border-radius: 3px;
+}
+
+QSlider::add-page:vertical {
+	width: 8px;
+	border-radius: 3px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #0F7DBE, stop:1 #1582C3); 
+}
+
+QSlider::handle:vertical {
+	height: 14px; 
+	margin-left: -3px;
+	margin-right: -3px;
+	border-radius: 6px;
+	background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #F0F0F0, stop:0.778409 #50A3F0);
+}
+
+QSlider::handle:vertical:hover {
+	background: qradialgradient(spread: pad, cx: 0.5, cy: 0.5, radius: 0.5, fx: 0.5, fy: 0.5, stop: 0.6 #F0F0F0,stop:0.778409 #0F7DBE);
+}
+
+QScrollBar:vertical {
+	width:10px; 
+	background-color:rgba(0,0,0,0%); 
+	padding-top:10px; 
+	padding-bottom:10px;
+}
+
+QScrollBar:horizontal {
+	height:10px; 
+	background-color:rgba(0,0,0,0%); 
+	padding-left:10px; padding-right:10px;
+}
+
+QScrollBar::handle:vertical {
+	width:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #50A3F0, stop:1 #489CEA); 
+}
+
+QScrollBar::handle:horizontal {
+	height:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #50A3F0, stop:1 #489CEA); 
+}
+
+QScrollBar::handle:vertical:hover {
+	width:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #0F7DBE, stop:1 #1582C3); 
+}
+
+QScrollBar::handle:horizontal:hover {
+	height:10px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #0F7DBE, stop:1 #1582C3); 
+}
+
+QScrollBar::add-line:vertical {
+	height:10px;
+	width:10px;
+	subcontrol-position: bottom; 
+	subcontrol-origin: margin;
+	border-image:url(:/image/add-line_vertical.png);
+}
+
+QScrollBar::add-line:horizontal {
+	height:10px;
+	width:10px;
+	subcontrol-position: right;
+	subcontrol-origin: margin;
+	border-image:url(:/image/add-line_horizontal.png);
+}
+
+QScrollBar::sub-line:vertical {
+	height:10px;
+	width:10px;
+	subcontrol-position: top; 
+	subcontrol-origin: margin;
+	border-image:url(:/image/sub-line_vertical.png);
+}
+
+QScrollBar::sub-line:horizontal {
+	height:10px;
+	width:10px;
+	subcontrol-position: left;
+	subcontrol-origin: margin;
+	border-image:url(:/image/sub-line_horizontal.png);
+}
+
+QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical {
+	width:10px;
+	background: #C0C0C0;
+}
+
+QScrollBar::add-page:horizontal,QScrollBar::sub-page:horizontal {
+	height:10px;
+	background: #C0C0C0;
+}
+
+QScrollArea {
+	border: 0px ; 
+}
+
+QTreeView,QListView,QTableView{
+	border: 1px solid #50A3F0; 
+	selection-background-color: #0F7DBE;
+	selection-color: #F0F0F0;
+}
+
+QTableView::item:selected, QListView::item:selected, QTreeView::item:selected {
+	color: #F0F0F0;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #0F7DBE, stop:1 #1582C3); 
+}
+
+QTableView::item:hover, QListView::item:hover, QTreeView::item:hover {
+	color: #F0F0F0;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #50A3F0, stop:1 #489CEA); 
+}
+
+QTableView::item, QListView::item, QTreeView::item {
+	padding: 5px; 
+	margin: 0px; 
+}
+
+QHeaderView::section {
+	padding:3px;
+	margin:0px;
+	color:#F0F0F0;
+	border: 1px solid #F0F0F0;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #50A3F0, stop:1 #489CEA);
+}
+
+QTabBar::tab {
+	border-bottom-left-radius:0px;
+	border-bottom-right-radius:0px;
+	color: #F0F0F0;
+	min-width: 60px;
+	min-height: 20px;
+	padding: 3px 8px 3px 8px;
+	margin:1px;
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #50A3F0, stop:1 #489CEA); 
+}
+
+QTabBar::tab:selected, QTabBar::tab:hover {
+	background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #0F7DBE, stop:1 #1582C3); 
+}
+
+QStatusBar::item {
+     border: 1px solid #50A3F0;
+     border-radius: 3px;
+}

二進制
src/CustomTitleWidget/image/qt_zh_CN.qm


二進制
src/CustomTitleWidget/image/question.png


二進制
src/CustomTitleWidget/image/radio_normal.png


二進制
src/CustomTitleWidget/image/radio_selected.png


二進制
src/CustomTitleWidget/image/sub-line_horizontal.png


二進制
src/CustomTitleWidget/image/sub-line_vertical.png


+ 121 - 0
src/CustomTitleWidget/myhelper.h

@@ -0,0 +1,121 @@
+#ifndef MYHELPER_H
+#define MYHELPER_H
+
+#include <QtCore>
+#include <QtGui>
+#include <QDesktopWidget>
+#include "frmmessagebox.h"
+
+class myHelper: public QObject
+{
+
+public:
+
+    //设置为开机启动
+    static void AutoRunWithSystem(bool IsAutoRun, QString AppName, QString AppPath)
+    {
+        QSettings *reg = new QSettings(
+            "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
+            QSettings::NativeFormat);
+
+        if (IsAutoRun) {
+            reg->setValue(AppName, AppPath);
+        } else {
+            reg->setValue(AppName, "");
+        }
+    }
+
+    //设置编码为UTF8
+    static void SetUTF8Code()
+    {
+#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
+        QTextCodec *codec = QTextCodec::codecForName("UTF-8");
+        QTextCodec::setCodecForLocale(codec);
+        QTextCodec::setCodecForCStrings(codec);
+        QTextCodec::setCodecForTr(codec);
+#endif
+    }
+
+	    //设置编码为GBK
+    static void SetGBKCode()
+    {
+#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
+        QTextCodec *codec = QTextCodec::codecForName("GBK");
+        QTextCodec::setCodecForLocale(codec);
+        QTextCodec::setCodecForCStrings(codec);
+        QTextCodec::setCodecForTr(codec);
+#endif
+    }
+
+    //设置皮肤样式
+    static void SetStyle(const QString &styleName)
+    {
+        QFile file(QString(":/image/%1.css").arg(styleName));
+        file.open(QFile::ReadOnly);
+        QString qss = QLatin1String(file.readAll());
+        qApp->setStyleSheet(qss);
+        qApp->setPalette(QPalette(QColor("#F0F0F0")));
+    }
+
+    //加载中文字符
+    static void SetChinese()
+    {
+        QTranslator *translator = new QTranslator(qApp);
+        translator->load(":/image/qt_zh_CN.qm");
+        qApp->installTranslator(translator);
+    }
+
+    //判断是否是IP地址
+    static bool IsIP(QString IP)
+    {
+        QRegExp RegExp("((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)");
+        return RegExp.exactMatch(IP);
+    }
+
+    //显示信息框,仅确定按钮
+    static void ShowMessageBoxInfo(QString info)
+    {
+        frmMessageBox *msg = new frmMessageBox;
+        msg->SetMessage(info, 0);
+        msg->exec();
+    }
+
+    //显示错误框,仅确定按钮
+    static void ShowMessageBoxError(QString info)
+    {
+        frmMessageBox *msg = new frmMessageBox;
+        msg->SetMessage(info, 2);
+        msg->exec();
+    }
+
+    //显示询问框,确定和取消按钮
+    static int ShowMessageBoxQuesion(QString info)
+    {
+        frmMessageBox *msg = new frmMessageBox;
+        msg->SetMessage(info, 1);
+        return msg->exec();
+    }
+
+    //延时
+    static void Sleep(int sec)
+    {
+        QTime dieTime = QTime::currentTime().addMSecs(sec);
+        while ( QTime::currentTime() < dieTime ) {
+            QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
+        }
+    }
+
+    //窗体居中显示
+    static void FormInCenter(QWidget *frm)
+    {
+        int frmX = frm->width();
+        int frmY = frm->height();
+        QDesktopWidget w;
+        int deskWidth = w.width();
+        int deskHeight = w.height();
+        QPoint movePoint(deskWidth / 2 - frmX / 2, deskHeight / 2 - frmY / 2);
+        frm->move(movePoint);
+    }
+};
+
+#endif // MYHELPER_H

+ 22 - 0
src/CustomTitleWidget/rc.qrc

@@ -0,0 +1,22 @@
+<RCC>
+    <qresource prefix="/">
+        <file>image/add-line_horizontal.png</file>
+        <file>image/add-line_vertical.png</file>
+        <file>image/array_down.png</file>
+        <file>image/checkbox_checked.png</file>
+        <file>image/checkbox_unchecked.png</file>
+        <file>image/error.png</file>
+        <file>image/fontawesome-webfont.ttf</file>
+        <file>image/info.png</file>
+        <file>image/qt_zh_CN.qm</file>
+        <file>image/question.png</file>
+        <file>image/radio_normal.png</file>
+        <file>image/radio_selected.png</file>
+        <file>image/sub-line_horizontal.png</file>
+        <file>image/sub-line_vertical.png</file>
+        <file>image/navy.css</file>
+        <file>image/black.css</file>
+        <file>image/blue.css</file>
+        <file>image/gray.css</file>
+    </qresource>
+</RCC>

+ 14 - 6
src/main.cpp

@@ -8,20 +8,28 @@
 #include <QApplication>
 #include <QTextCodec>
 
-#include "mainwindow.h"
+#include "videoplayer/videoplayer.h"
+#include "CustomTitleWidget/myhelper.h"
 
 #undef main
 int main(int argc, char *argv[])
 {
     QApplication a(argc, argv);
 
-    QTextCodec *codec = QTextCodec::codecForName("UTF-8"); //设置编码格式为UTF-8
-    QTextCodec::setCodecForLocale(codec);
-    QTextCodec::setCodecForCStrings(codec);
-    QTextCodec::setCodecForTr(codec);
+//    QTextCodec *codec = QTextCodec::codecForName("UTF-8");
+//    QTextCodec::setCodecForLocale(codec);
+//    QTextCodec::setCodecForCStrings(codec);
+//    QTextCodec::setCodecForTr(codec);
 
+    myHelper::SetUTF8Code();
+//    myHelper::SetStyle("black");//黑色风格
+//    myHelper::SetStyle("blue");//蓝色风格
+    myHelper::SetStyle("gray");//灰色风格
+//    myHelper::SetStyle("navy");//天蓝色风格
+    myHelper::SetChinese();
 
-    MainWindow w;
+
+    VideoPlayer w;
     w.show();
 
     return a.exec();

+ 0 - 156
src/mainwindow.cpp

@@ -1,156 +0,0 @@
-/**
- * 叶海辉
- * QQ群121376426
- * http://blog.yundiantech.com/
- */
-
-
-#include "mainwindow.h"
-#include "ui_mainwindow.h"
-
-#include <QPainter>
-#include <QPaintEvent>
-#include <QFileDialog>
-#include <QDebug>
-
-MainWindow::MainWindow(QWidget *parent) :
-    QMainWindow(parent),
-    ui(new Ui::MainWindow)
-{
-    ui->setupUi(this);
-
-
-    av_register_all(); //初始化FFMPEG  调用了这个才能正常使用编码器和解码器
-    avformat_network_init(); //支持打开网络文件
-
-    if (SDL_Init(SDL_INIT_AUDIO)) {
-        fprintf(stderr,"Could not initialize SDL - %s. \n", SDL_GetError());
-        exit(1);
-    }
-
-    mPlayer = new VideoPlayer;
-    connect(mPlayer,SIGNAL(sig_GetOneFrame(QImage)),this,SLOT(slotGetOneFrame(QImage)));
-    connect(mPlayer,SIGNAL(sig_TotalTimeChanged(qint64)),this,SLOT(slotTotalTimeChanged(qint64)));
-    connect(mPlayer,SIGNAL(sig_StateChanged(VideoPlayer::PlayerState)),this,SLOT(slotStateChanged(VideoPlayer::PlayerState)));
-
-
-    mTimer = new QTimer; //定时器-获取当前视频时间
-    connect(mTimer,SIGNAL(timeout()),this,SLOT(slotTimerTimeOut()));
-    mTimer->setInterval(500);
-
-    connect(ui->pushButton_open,SIGNAL(clicked()),this,SLOT(slotBtnClick()));
-    connect(ui->pushButton_play,SIGNAL(clicked()),this,SLOT(slotBtnClick()));
-    connect(ui->pushButton_pause,SIGNAL(clicked()),this,SLOT(slotBtnClick()));
-    connect(ui->pushButton_stop,SIGNAL(clicked()),this,SLOT(slotBtnClick()));
-
-    connect(ui->horizontalSlider,SIGNAL(sliderMoved(int)),this,SLOT(slotSliderMoved(int)));
-
-}
-
-MainWindow::~MainWindow()
-{
-    delete ui;
-}
-
-void MainWindow::paintEvent(QPaintEvent *event)
-{
-    QPainter painter(this);
-    painter.setBrush(Qt::black);
-    painter.drawRect(0, 0, this->width(), this->height()); //先画成黑色
-
-    if (mImage.size().width() <= 0) return;
-
-    ///将图像按比例缩放成和窗口一样大小
-    QImage img = mImage.scaled(this->size(),Qt::KeepAspectRatio);
-
-    int x = this->width() - img.width();
-    int y = this->height() - img.height();
-
-    x /= 2;
-    y /= 2;
-
-    painter.drawImage(QPoint(x,y),img); //画出图像
-
-}
-
-void MainWindow::slotGetOneFrame(QImage img)
-{
-    mImage = img;
-    update(); //调用update将执行 paintEvent函数
-}
-
-void MainWindow::slotTotalTimeChanged(qint64 uSec)
-{
-    qint64 Sec = uSec/1000000;
-
-    ui->horizontalSlider->setRange(0,Sec);
-
-//    QString hStr = QString("00%1").arg(Sec/3600);
-    QString mStr = QString("00%1").arg(Sec/60);
-    QString sStr = QString("00%1").arg(Sec%60);
-
-    QString str = QString("%1:%2").arg(mStr.right(2)).arg(sStr.right(2));
-    ui->label_totaltime->setText(str);
-
-}
-
-void MainWindow::slotSliderMoved(int value)
-{
-    if (QObject::sender() == ui->horizontalSlider)
-    {
-        mPlayer->seek((qint64)value * 1000000);
-    }
-}
-
-void MainWindow::slotTimerTimeOut()
-{
-    if (QObject::sender() == mTimer)
-    {
-
-        qint64 Sec = mPlayer->getCurrentTime();
-
-        ui->horizontalSlider->setValue(Sec);
-
-    //    QString hStr = QString("00%1").arg(Sec/3600);
-        QString mStr = QString("00%1").arg(Sec/60);
-        QString sStr = QString("00%1").arg(Sec%60);
-
-        QString str = QString("%1:%2").arg(mStr.right(2)).arg(sStr.right(2));
-        ui->label_currenttime->setText(str);
-    }
-}
-
-void MainWindow::slotBtnClick()
-{
-    if (QObject::sender() == ui->pushButton_play)
-    {
-        mPlayer->play();
-    }
-    else if (QObject::sender() == ui->pushButton_pause)
-    {
-        mPlayer->pause();
-    }
-    else if (QObject::sender() == ui->pushButton_stop)
-    {
-        mPlayer->stop(true);
-    }
-    else if (QObject::sender() == ui->pushButton_open)
-    {
-        QString s = QFileDialog::getOpenFileName(
-                   this, "选择要播放的文件",
-                    "/",//初始目录
-                    "视频文件 (*.flv *.rmvb *.avi *.MP4);; 所有文件 (*.*);; ");
-        if (!s.isEmpty())
-        {
-            s.replace("/","\\");
-
-            mPlayer->stop(true); //如果在播放则先停止
-
-            mPlayer->setFileName(s);
-
-            mTimer->start();
-
-        }
-    }
-
-}

+ 0 - 53
src/mainwindow.h

@@ -1,53 +0,0 @@
-/**
- * 叶海辉
- * QQ群121376426
- * http://blog.yundiantech.com/
- */
-
-#ifndef MAINWINDOW_H
-#define MAINWINDOW_H
-
-#include <QMainWindow>
-#include <QImage>
-#include <QPaintEvent>
-#include <QTimer>
-
-#include "videoplayer/videoplayer.h"
-
-namespace Ui {
-class MainWindow;
-}
-
-class MainWindow : public QMainWindow
-{
-    Q_OBJECT
-
-public:
-    explicit MainWindow(QWidget *parent = 0);
-    ~MainWindow();
-
-protected:
-    void paintEvent(QPaintEvent *event);
-
-private:
-    Ui::MainWindow *ui;
-
-    VideoPlayer *mPlayer; //播放线程
-
-    QImage mImage; //记录当前的图像
-
-    QTimer *mTimer; //定时器-获取当前视频时间
-
-private slots:
-    void slotGetOneFrame(QImage img);
-
-    void slotTotalTimeChanged(qint64 uSec);
-
-    void slotSliderMoved(int value);
-
-    void slotTimerTimeOut();
-
-    void slotBtnClick();
-};
-
-#endif // MAINWINDOW_H

+ 0 - 142
src/mainwindow.ui

@@ -1,142 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MainWindow</class>
- <widget class="QMainWindow" name="MainWindow">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>832</width>
-    <height>540</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>MainWindow</string>
-  </property>
-  <widget class="QWidget" name="centralwidget">
-   <layout class="QVBoxLayout" name="verticalLayout">
-    <item>
-     <spacer name="verticalSpacer">
-      <property name="orientation">
-       <enum>Qt::Vertical</enum>
-      </property>
-      <property name="sizeHint" stdset="0">
-       <size>
-        <width>20</width>
-        <height>378</height>
-       </size>
-      </property>
-     </spacer>
-    </item>
-    <item>
-     <widget class="QWidget" name="widget_controller" native="true">
-      <property name="minimumSize">
-       <size>
-        <width>0</width>
-        <height>32</height>
-       </size>
-      </property>
-      <property name="maximumSize">
-       <size>
-        <width>16777215</width>
-        <height>32</height>
-       </size>
-      </property>
-      <property name="styleSheet">
-       <string notr="true">QWidget#widget_controller
-{
-	background-color: rgba(0, 255, 0, 100);
-}</string>
-      </property>
-      <layout class="QHBoxLayout" name="horizontalLayout_2">
-       <property name="topMargin">
-        <number>0</number>
-       </property>
-       <property name="bottomMargin">
-        <number>0</number>
-       </property>
-       <item>
-        <widget class="QPushButton" name="pushButton_open">
-         <property name="text">
-          <string>打开视频</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QPushButton" name="pushButton_play">
-         <property name="text">
-          <string>播放</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QPushButton" name="pushButton_pause">
-         <property name="text">
-          <string>暂停</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QPushButton" name="pushButton_stop">
-         <property name="text">
-          <string>停止</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QSlider" name="horizontalSlider">
-         <property name="orientation">
-          <enum>Qt::Horizontal</enum>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <layout class="QHBoxLayout" name="horizontalLayout">
-         <item>
-          <widget class="QLabel" name="label_currenttime">
-           <property name="text">
-            <string>00:00:00</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QLabel" name="label_2">
-           <property name="text">
-            <string>/</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QLabel" name="label_totaltime">
-           <property name="text">
-            <string>00:00:00</string>
-           </property>
-          </widget>
-         </item>
-        </layout>
-       </item>
-      </layout>
-      <zorder>pushButton_play</zorder>
-      <zorder>pushButton_pause</zorder>
-      <zorder>pushButton_stop</zorder>
-      <zorder>horizontalSlider</zorder>
-      <zorder>pushButton_open</zorder>
-     </widget>
-    </item>
-   </layout>
-  </widget>
-  <widget class="QMenuBar" name="menubar">
-   <property name="geometry">
-    <rect>
-     <x>0</x>
-     <y>0</y>
-     <width>832</width>
-     <height>23</height>
-    </rect>
-   </property>
-  </widget>
-  <widget class="QStatusBar" name="statusbar"/>
- </widget>
- <resources/>
- <connections/>
-</ui>

+ 110 - 932
src/videoplayer/videoplayer.cpp

@@ -5,1010 +5,188 @@
  */
 
 #include "videoplayer.h"
+#include "ui_videoplayer.h"
 
-#include <stdio.h>
-
+#include <QPainter>
+#include <QPaintEvent>
+#include <QFileDialog>
 #include <QDebug>
+#include <QDesktopWidget>
+#include <QFontDatabase>
+#include <QMouseEvent>
 
-#define SDL_AUDIO_BUFFER_SIZE 1024
-#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
-
-#define FLUSH_DATA "FLUSH"
-
-void packet_queue_init(PacketQueue *q) {
-    memset(q, 0, sizeof(PacketQueue));
-    q->mutex = SDL_CreateMutex();
-    q->cond = SDL_CreateCond();
-    q->size = 0;
-    q->nb_packets = 0;
-    q->first_pkt = NULL;
-    q->last_pkt = NULL;
-}
-
-int packet_queue_put(PacketQueue *q, AVPacket *pkt) {
-
-    AVPacketList *pkt1;
-    if (av_dup_packet(pkt) < 0) {
-        return -1;
-    }
-    pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList));
-    if (!pkt1)
-        return -1;
-    pkt1->pkt = *pkt;
-    pkt1->next = NULL;
-
-    SDL_LockMutex(q->mutex);
-
-    if (!q->last_pkt)
-        q->first_pkt = pkt1;
-    else
-        q->last_pkt->next = pkt1;
-    q->last_pkt = pkt1;
-    q->nb_packets++;
-    q->size += pkt1->pkt.size;
-    SDL_CondSignal(q->cond);
-
-    SDL_UnlockMutex(q->mutex);
-    return 0;
-}
-
-static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) {
-    AVPacketList *pkt1;
-    int ret;
-
-    SDL_LockMutex(q->mutex);
-
-    for (;;) {
-
-        pkt1 = q->first_pkt;
-        if (pkt1) {
-            q->first_pkt = pkt1->next;
-            if (!q->first_pkt)
-                q->last_pkt = NULL;
-            q->nb_packets--;
-            q->size -= pkt1->pkt.size;
-            *pkt = pkt1->pkt;
-            av_free(pkt1);
-            ret = 1;
-            break;
-        } else if (!block) {
-            ret = 0;
-            break;
-        } else {
-            SDL_CondWait(q->cond, q->mutex);
-        }
-
-    }
-
-    SDL_UnlockMutex(q->mutex);
-    return ret;
-}
+Q_DECLARE_METATYPE(VideoPlayer_Thread::PlayerState);
 
-static void packet_queue_flush(PacketQueue *q)
+VideoPlayer::VideoPlayer(QWidget *parent) :
+    CustomTitle(parent),
+    ui(new Ui::VideoPlayer)
 {
-    AVPacketList *pkt, *pkt1;
+    ui->setupUi(getContentDialog());
 
-    SDL_LockMutex(q->mutex);
-    for(pkt = q->first_pkt; pkt != NULL; pkt = pkt1)
-    {
-        pkt1 = pkt->next;
-
-        if(pkt1->pkt.data != (uint8_t *)"FLUSH")
-        {
-
-        }
-        av_free_packet(&pkt->pkt);
-        av_freep(&pkt);
+    av_register_all(); //初始化FFMPEG  调用了这个才能正常使用编码器和解码器
+    avformat_network_init(); //支持打开网络文件
 
+    if (SDL_Init(SDL_INIT_AUDIO)) {
+        fprintf(stderr,"Could not initialize SDL - %s. \n", SDL_GetError());
+        exit(1);
     }
-    q->last_pkt = NULL;
-    q->first_pkt = NULL;
-    q->nb_packets = 0;
-    q->size = 0;
-    SDL_UnlockMutex(q->mutex);
-}
 
-static int audio_decode_frame(VideoState *is, double *pts_ptr)
-{
-    int len1, len2, decoded_data_size;
-    AVPacket *pkt = &is->audio_pkt;
-    int got_frame = 0;
-    int64_t dec_channel_layout;
-    int wanted_nb_samples, resampled_data_size, n;
-
-    double pts;
-
-    for (;;) {
-
-        while (is->audio_pkt_size > 0) {
-
-            if (is->isPause == true) //判断暂停
-            {
-                SDL_Delay(10);
-                continue;
-            }
-
-            if (!is->audio_frame) {
-                if (!(is->audio_frame = avcodec_alloc_frame())) {
-                    return AVERROR(ENOMEM);
-                }
-            } else
-                avcodec_get_frame_defaults(is->audio_frame);
-
-            len1 = avcodec_decode_audio4(is->audio_st->codec, is->audio_frame,
-                    &got_frame, pkt);
-            if (len1 < 0) {
-                // error, skip the frame
-                is->audio_pkt_size = 0;
-                break;
-            }
-
-            is->audio_pkt_data += len1;
-            is->audio_pkt_size -= len1;
-
-            if (!got_frame)
-                continue;
-
-            /* 计算解码出来的桢需要的缓冲大小 */
-            decoded_data_size = av_samples_get_buffer_size(NULL,
-                    is->audio_frame->channels, is->audio_frame->nb_samples,
-                    (AVSampleFormat)is->audio_frame->format, 1);
-
-            dec_channel_layout =
-                    (is->audio_frame->channel_layout
-                            && is->audio_frame->channels
-                                    == av_get_channel_layout_nb_channels(
-                                            is->audio_frame->channel_layout)) ?
-                            is->audio_frame->channel_layout :
-                            av_get_default_channel_layout(
-                                    is->audio_frame->channels);
-
-            wanted_nb_samples = is->audio_frame->nb_samples;
-
-            if (is->audio_frame->format != is->audio_src_fmt
-                    || dec_channel_layout != is->audio_src_channel_layout
-                    || is->audio_frame->sample_rate != is->audio_src_freq
-                    || (wanted_nb_samples != is->audio_frame->nb_samples
-                            && !is->swr_ctx)) {
-                if (is->swr_ctx)
-                    swr_free(&is->swr_ctx);
-                is->swr_ctx = swr_alloc_set_opts(NULL,
-                        is->audio_tgt_channel_layout, (AVSampleFormat)is->audio_tgt_fmt,
-                        is->audio_tgt_freq, dec_channel_layout,
-                        (AVSampleFormat)is->audio_frame->format, is->audio_frame->sample_rate,
-                        0, NULL);
-                if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {
-                    //fprintf(stderr,"swr_init() failed\n");
-                    break;
-                }
-                is->audio_src_channel_layout = dec_channel_layout;
-                is->audio_src_channels = is->audio_st->codec->channels;
-                is->audio_src_freq = is->audio_st->codec->sample_rate;
-                is->audio_src_fmt = is->audio_st->codec->sample_fmt;
-            }
-
-            /* 这里我们可以对采样数进行调整,增加或者减少,一般可以用来做声画同步 */
-            if (is->swr_ctx) {
-                const uint8_t **in =
-                        (const uint8_t **) is->audio_frame->extended_data;
-                uint8_t *out[] = { is->audio_buf2 };
-                if (wanted_nb_samples != is->audio_frame->nb_samples) {
-                    if (swr_set_compensation(is->swr_ctx,
-                            (wanted_nb_samples - is->audio_frame->nb_samples)
-                                    * is->audio_tgt_freq
-                                    / is->audio_frame->sample_rate,
-                            wanted_nb_samples * is->audio_tgt_freq
-                                    / is->audio_frame->sample_rate) < 0) {
-                        //fprintf(stderr,"swr_set_compensation() failed\n");
-                        break;
-                    }
-                }
-
-                len2 = swr_convert(is->swr_ctx, out,
-                        sizeof(is->audio_buf2) / is->audio_tgt_channels
-                                / av_get_bytes_per_sample(is->audio_tgt_fmt),
-                        in, is->audio_frame->nb_samples);
-                if (len2 < 0) {
-                    //fprintf(stderr,"swr_convert() failed\n");
-                    break;
-                }
-                if (len2
-                        == sizeof(is->audio_buf2) / is->audio_tgt_channels
-                                / av_get_bytes_per_sample(is->audio_tgt_fmt)) {
-                    //fprintf(stderr,"warning: audio buffer is probably too small\n");
-                    swr_init(is->swr_ctx);
-                }
-                is->audio_buf = is->audio_buf2;
-                resampled_data_size = len2 * is->audio_tgt_channels
-                        * av_get_bytes_per_sample(is->audio_tgt_fmt);
-            } else {
-                resampled_data_size = decoded_data_size;
-                is->audio_buf = is->audio_frame->data[0];
-            }
-
-            pts = is->audio_clock;
-            *pts_ptr = pts;
-            n = 2 * is->audio_st->codec->channels;
-            is->audio_clock += (double) resampled_data_size
-                    / (double) (n * is->audio_st->codec->sample_rate);
-
-
-            if (is->seek_flag_audio)
-            {
-                //发生了跳转 则跳过关键帧到目的时间的这几帧
-               if (is->audio_clock < is->seek_time)
-               {
-                   break;
-               }
-               else
-               {
-                   is->seek_flag_audio = 0;
-               }
-            }
-
-
-            // We have data, return it and come back for more later
-            return resampled_data_size;
-        }
+    //因为VideoPlayer::PlayerState是自定义的类型 要跨线程传递需要先注册一下
+    qRegisterMetaType<VideoPlayer_Thread::PlayerState>();
 
-        if (is->isPause == true) //判断暂停
-        {
-            SDL_Delay(10);
-            continue;
-        }
 
-        if (pkt->data)
-            av_free_packet(pkt);
-        memset(pkt, 0, sizeof(*pkt));
+    mPlayer = new VideoPlayer_Thread;
+    connect(mPlayer,SIGNAL(sig_TotalTimeChanged(qint64)),this,SLOT(slotTotalTimeChanged(qint64)));
+    connect(mPlayer,SIGNAL(sig_StateChanged(VideoPlayer_Thread::PlayerState)),this,SLOT(slotStateChanged(VideoPlayer_Thread::PlayerState)));
 
-        if (is->quit)
-            return -1;
+    ui->verticalLayout_show_video->addWidget(mPlayer->getVideoWidget()); //将显示视频的控件加入
+    mPlayer->getVideoWidget()->show();
 
-        if (packet_queue_get(&is->audioq, pkt, 0) <= 0)
-        {
-            return -1;
-        }
+    mTimer = new QTimer; //定时器-获取当前视频时间
+    connect(mTimer,SIGNAL(timeout()),this,SLOT(slotTimerTimeOut()));
+    mTimer->setInterval(500);
 
-        //收到这个数据 说明刚刚执行过跳转 现在需要把解码器的数据 清除一下
-        if(strcmp((char*)pkt->data,FLUSH_DATA) == 0)
-        {
-            avcodec_flush_buffers(is->audio_st->codec);
-            av_free_packet(pkt);
-            continue;
-        }
+    connect(ui->pushButton_open,SIGNAL(clicked()),this,SLOT(slotBtnClick()));
+    connect(ui->toolButton_open,SIGNAL(clicked()),this,SLOT(slotBtnClick()));
+    connect(ui->pushButton_play,SIGNAL(clicked()),this,SLOT(slotBtnClick()));
+    connect(ui->pushButton_pause,SIGNAL(clicked()),this,SLOT(slotBtnClick()));
+    connect(ui->pushButton_stop,SIGNAL(clicked()),this,SLOT(slotBtnClick()));
 
-        is->audio_pkt_data = pkt->data;
-        is->audio_pkt_size = pkt->size;
+//    connect(ui->horizontalSlider,SIGNAL(sliderMoved(int)),this,SLOT(slotSliderMoved(int)));
+    connect(ui->horizontalSlider,SIGNAL(sig_valueChanged(int)),this,SLOT(slotSliderMoved(int)));
 
-        /* if update, update the audio clock w/pts */
-        if (pkt->pts != AV_NOPTS_VALUE) {
-            is->audio_clock = av_q2d(is->audio_st->time_base) * pkt->pts;
-        }
-    }
+    resize(1024,768);
+    setTitle("我的播放器");
 
-    return 0;
-}
+    ui->widget_right->hide();
+    ui->widget_video->hide();
 
-
-static void audio_callback(void *userdata, Uint8 *stream, int len) {
-    VideoState *is = (VideoState *) userdata;
-
-    int len1, audio_data_size;
-
-    double pts;
-
-    /*   len是由SDL传入的SDL缓冲区的大小,如果这个缓冲未满,我们就一直往里填充数据 */
-    while (len > 0) {
-        /*  audio_buf_index 和 audio_buf_size 标示我们自己用来放置解码出来的数据的缓冲区,*/
-        /*   这些数据待copy到SDL缓冲区, 当audio_buf_index >= audio_buf_size的时候意味着我*/
-        /*   们的缓冲为空,没有数据可供copy,这时候需要调用audio_decode_frame来解码出更
-         /*   多的桢数据 */
-        if (is->audio_buf_index >= is->audio_buf_size) {
-
-            audio_data_size = audio_decode_frame(is, &pts);
-
-            /* audio_data_size < 0 标示没能解码出数据,我们默认播放静音 */
-            if (audio_data_size < 0) {
-                /* silence */
-                is->audio_buf_size = 1024;
-                /* 清零,静音 */
-                if (is->audio_buf == NULL) return;
-                memset(is->audio_buf, 0, is->audio_buf_size);
-            } else {
-                is->audio_buf_size = audio_data_size;
-            }
-            is->audio_buf_index = 0;
-        }
-        /*  查看stream可用空间,决定一次copy多少数据,剩下的下次继续copy */
-        len1 = is->audio_buf_size - is->audio_buf_index;
-        if (len1 > len) {
-            len1 = len;
-        }
-
-        if (is->audio_buf == NULL) return;
-
-        memcpy(stream, (uint8_t *) is->audio_buf + is->audio_buf_index, len1);
-//        SDL_MixAudio(stream, (uint8_t * )is->audio_buf + is->audio_buf_index, len1, 50);
-
-//        SDL_MixAudioFormat(stream, (uint8_t * )is->audio_buf + is->audio_buf_index, AUDIO_S16SYS, len1, 50);
-
-        len -= len1;
-        stream += len1;
-        is->audio_buf_index += len1;
-    }
+    ui->pushButton_pause->hide();
 
 }
 
-static double get_audio_clock(VideoState *is)
+VideoPlayer::~VideoPlayer()
 {
-    double pts;
-    int hw_buf_size, bytes_per_sec, n;
-
-    pts = is->audio_clock; /* maintained in the audio thread */
-    hw_buf_size = is->audio_buf_size - is->audio_buf_index;
-    bytes_per_sec = 0;
-    n = is->audio_st->codec->channels * 2;
-    if(is->audio_st)
-    {
-        bytes_per_sec = is->audio_st->codec->sample_rate * n;
-    }
-    if(bytes_per_sec)
-    {
-        pts -= (double)hw_buf_size / bytes_per_sec;
-    }
-    return pts;
-}
-
-static double synchronize_video(VideoState *is, AVFrame *src_frame, double pts) {
-
-    double frame_delay;
-
-    if (pts != 0) {
-        /* if we have pts, set video clock to it */
-        is->video_clock = pts;
-    } else {
-        /* if we aren't given a pts, set it to the clock */
-        pts = is->video_clock;
-    }
-    /* update the video clock */
-    frame_delay = av_q2d(is->video_st->codec->time_base);
-    /* if we are repeating a frame, adjust clock accordingly */
-    frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
-    is->video_clock += frame_delay;
-    return pts;
+    delete ui;
 }
 
-int audio_stream_component_open(VideoState *is, int stream_index)
+void VideoPlayer::doClose()
 {
-    AVFormatContext *ic = is->ic;
-    AVCodecContext *codecCtx;
-    AVCodec *codec;
-    SDL_AudioSpec wanted_spec, spec;
-    int64_t wanted_channel_layout = 0;
-    int wanted_nb_channels;
-    /*  SDL支持的声道数为 1, 2, 4, 6 */
-    /*  后面我们会使用这个数组来纠正不支持的声道数目 */
-    const int next_nb_channels[] = { 0, 0, 1, 6, 2, 6, 4, 6 };
-
-    if (stream_index < 0 || stream_index >= ic->nb_streams) {
-        return -1;
-    }
-
-    codecCtx = ic->streams[stream_index]->codec;
-    wanted_nb_channels = codecCtx->channels;
-    if (!wanted_channel_layout
-            || wanted_nb_channels
-                    != av_get_channel_layout_nb_channels(
-                            wanted_channel_layout)) {
-        wanted_channel_layout = av_get_default_channel_layout(
-                wanted_nb_channels);
-        wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
-    }
+    mPlayer->stop(true);
+    close();
+}
 
-    wanted_spec.channels = av_get_channel_layout_nb_channels(
-            wanted_channel_layout);
-    wanted_spec.freq = codecCtx->sample_rate;
-    if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
-        //fprintf(stderr,"Invalid sample rate or channel count!\n");
-        return -1;
-    }
-    wanted_spec.format = AUDIO_S16SYS; // 具体含义请查看“SDL宏定义”部分
-    wanted_spec.silence = 0;            // 0指示静音
-    wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;  // 自定义SDL缓冲区大小
-    wanted_spec.callback = audio_callback;        // 音频解码的关键回调函数
-    wanted_spec.userdata = is;                    // 传给上面回调函数的外带数据
-
-//    SDL_AudioDeviceID audioID = 1;// = SDL_OpenAudioDevice("",0,&wanted_spec, &spec,1);
-//    int num = SDL_GetNumAudioDevices(0);
-//    for (int i=0;i<num;i++)
+//void VideoPlayer::mousePressEvent(QMouseEvent *e)
+//{qDebug()<<"ccc";
+//    if (e->button() == Qt::LeftButton)
 //    {
-//        qDebug()<<SDL_GetAudioDeviceName(i,0);
-//    }
 
-//    ///  打开SDL播放设备 - 开始
-//    SDL_LockAudio();
-//    SDL_AudioSpec spec;
-//    SDL_AudioSpec wanted_spec;
-//    wanted_spec.freq = aCodecCtx->sample_rate;
-//    wanted_spec.format = AUDIO_S16SYS;
-//    wanted_spec.channels = aCodecCtx->channels;
-//    wanted_spec.silence = 0;
-//    wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
-//    wanted_spec.callback = audio_callback;
-//    wanted_spec.userdata = &mVideoState;
-//    if(SDL_OpenAudio(&wanted_spec, &spec) < 0)
-//    {
-//        fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
-//        return;
 //    }
-//    SDL_UnlockAudio();
-//    SDL_PauseAudio(0);
-//    ///  打开SDL播放设备 - 结束
+//}
 
-    /*  打开音频设备,这里使用一个while来循环尝试打开不同的声道数(由上面 */
-    /*  next_nb_channels数组指定)直到成功打开,或者全部失败 */
-//    while (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
-    do {
+//void VideoPlayer::mouseDoubleClickEvent(QMouseEvent *e)
+//{
+//    qDebug()<<"ddd";
+////    if (e->type() == Qt::mou)
+//}
 
-        is->audioID = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(0,0),0,&wanted_spec, &spec,0);
-
-//        qDebug()<<"audioID"<<audioID;
-
-//        if (audioID >= 1) break;
-
-        fprintf(stderr,"SDL_OpenAudio (%d channels): %s\n",wanted_spec.channels, SDL_GetError());
-        qDebug()<<QString("SDL_OpenAudio (%1 channels): %2").arg(wanted_spec.channels).arg(SDL_GetError());
-        wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];
-        if (!wanted_spec.channels) {
-            fprintf(stderr,"No more channel combinations to tyu, audio open failed\n");
-//            return -1;
-            break;
-        }
-        wanted_channel_layout = av_get_default_channel_layout(
-                wanted_spec.channels);
-    }while(is->audioID == 0);
-
-    /* 检查实际使用的配置(保存在spec,由SDL_OpenAudio()填充) */
-    if (spec.format != AUDIO_S16SYS) {
-        fprintf(stderr,"SDL advised audio format %d is not supported!\n",spec.format);
-        return -1;
-    }
-
-    if (spec.channels != wanted_spec.channels) {
-        wanted_channel_layout = av_get_default_channel_layout(spec.channels);
-        if (!wanted_channel_layout) {
-            fprintf(stderr,"SDL advised channel count %d is not supported!\n",spec.channels);
-            return -1;
-        }
-    }
-
-    is->audio_hw_buf_size = spec.size;
-
-    /* 把设置好的参数保存到大结构中 */
-    is->audio_src_fmt = is->audio_tgt_fmt = AV_SAMPLE_FMT_S16;
-    is->audio_src_freq = is->audio_tgt_freq = spec.freq;
-    is->audio_src_channel_layout = is->audio_tgt_channel_layout =
-            wanted_channel_layout;
-    is->audio_src_channels = is->audio_tgt_channels = spec.channels;
-
-    codec = avcodec_find_decoder(codecCtx->codec_id);
-    if (!codec || (avcodec_open2(codecCtx, codec, NULL) < 0)) {
-        fprintf(stderr,"Unsupported codec!\n");
-        return -1;
-    }
-    ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
-    switch (codecCtx->codec_type) {
-    case AVMEDIA_TYPE_AUDIO:
-//        is->audioStream = stream_index;
-        is->audio_st = ic->streams[stream_index];
-        is->audio_buf_size = 0;
-        is->audio_buf_index = 0;
-        memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
-        packet_queue_init(&is->audioq);
-//        SDL_PauseAudio(0); // 开始播放静音
-        SDL_PauseAudioDevice(is->audioID,0);
-        break;
-    default:
-        break;
-    }
-
-    return 0;
-}
-
-int video_thread(void *arg)
+void VideoPlayer::slotTotalTimeChanged(qint64 uSec)
 {
-    VideoState *is = (VideoState *) arg;
-    AVPacket pkt1, *packet = &pkt1;
-
-    int ret, got_picture, numBytes;
-
-    double video_pts = 0; //当前视频的pts
-    double audio_pts = 0; //音频pts
-
-
-    ///解码视频相关
-    AVFrame *pFrame, *pFrameRGB;
-    uint8_t *out_buffer_rgb; //解码后的rgb数据
-    struct SwsContext *img_convert_ctx;  //用于解码后的视频格式转换
-
-    AVCodecContext *pCodecCtx = is->video_st->codec; //视频解码器
-
-    pFrame = av_frame_alloc();
-    pFrameRGB = av_frame_alloc();
-
-    ///这里我们改成了 将解码后的YUV数据转换成RGB32
-    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
-            pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
-            PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
-
-    numBytes = avpicture_get_size(PIX_FMT_RGB32, pCodecCtx->width,pCodecCtx->height);
-
-    out_buffer_rgb = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
-    avpicture_fill((AVPicture *) pFrameRGB, out_buffer_rgb, PIX_FMT_RGB32,
-            pCodecCtx->width, pCodecCtx->height);
-
-    while(1)
-    {
-        if (is->quit)
-        {
-            break;
-        }
-
-        if (is->isPause == true) //判断暂停
-        {
-            SDL_Delay(10);
-            continue;
-        }
-
-        if (packet_queue_get(&is->videoq, packet, 0) <= 0)
-        {
-            if (is->readFinished)
-            {//队列里面没有数据了且读取完毕了
-                break;
-            }
-            else
-            {
-                SDL_Delay(1); //队列只是暂时没有数据而已
-                continue;
-            }
-        }
-
-        //收到这个数据 说明刚刚执行过跳转 现在需要把解码器的数据 清除一下
-        if(strcmp((char*)packet->data,FLUSH_DATA) == 0)
-        {
-            avcodec_flush_buffers(is->video_st->codec);
-            av_free_packet(packet);
-            continue;
-        }
-
-        ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,packet);
-
-        if (ret < 0) {
-            qDebug()<<"decode error.\n";
-            av_free_packet(packet);
-            continue;
-        }
-
-        if (packet->dts == AV_NOPTS_VALUE && pFrame->opaque&& *(uint64_t*) pFrame->opaque != AV_NOPTS_VALUE)
-        {
-            video_pts = *(uint64_t *) pFrame->opaque;
-        }
-        else if (packet->dts != AV_NOPTS_VALUE)
-        {
-            video_pts = packet->dts;
-        }
-        else
-        {
-            video_pts = 0;
-        }
-
-        video_pts *= av_q2d(is->video_st->time_base);
-        video_pts = synchronize_video(is, pFrame, video_pts);
-
-        if (is->seek_flag_video)
-        {
-            //发生了跳转 则跳过关键帧到目的时间的这几帧
-           if (video_pts < is->seek_time)
-           {
-               av_free_packet(packet);
-               continue;
-           }
-           else
-           {
-               is->seek_flag_video = 0;
-           }
-        }
-
-        while(1)
-        {
-            if (is->quit)
-            {
-                break;
-            }
-
-            audio_pts = is->audio_clock;
-
-            //主要是 跳转的时候 我们把video_clock设置成0了
-            //因此这里需要更新video_pts
-            //否则当从后面跳转到前面的时候 会卡在这里
-            video_pts = is->video_clock;
-
-
-            if (video_pts <= audio_pts) break;
-
-            int delayTime = (video_pts - audio_pts) * 1000;
-
-            delayTime = delayTime > 5 ? 5:delayTime;
-
-            SDL_Delay(delayTime);
-        }
-
-        if (got_picture) {
-            sws_scale(img_convert_ctx,
-                    (uint8_t const * const *) pFrame->data,
-                    pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,
-                    pFrameRGB->linesize);
-
-            //把这个RGB数据 用QImage加载
-            QImage tmpImg((uchar *)out_buffer_rgb,pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB32);
-            QImage image = tmpImg.copy(); //把图像复制一份 传递给界面显示
-            is->player->disPlayVideo(image); //调用激发信号的函数
-        }
-
-        av_free_packet(packet);
-
-    }
-
-    av_free(pFrame);
-    av_free(pFrameRGB);
-    av_free(out_buffer_rgb);
+    qint64 Sec = uSec/1000000;
 
-    if (!is->quit)
-    {
-        is->quit = true;
-    }
+    ui->horizontalSlider->setRange(0,Sec);
 
-    is->videoThreadFinished = true;
-
-    return 0;
-}
+//    QString hStr = QString("00%1").arg(Sec/3600);
+    QString mStr = QString("00%1").arg(Sec/60);
+    QString sStr = QString("00%1").arg(Sec%60);
 
+    QString str = QString("%1:%2").arg(mStr.right(2)).arg(sStr.right(2));
+    ui->label_totaltime->setText(str);
 
-VideoPlayer::VideoPlayer()
-{
-    mPlayerState = Stop;
 }
 
-VideoPlayer::~VideoPlayer()
+void VideoPlayer::slotSliderMoved(int value)
 {
-
-}
-
-bool VideoPlayer::setFileName(QString path)
-{
-    if (mPlayerState != Stop)
+    if (QObject::sender() == ui->horizontalSlider)
     {
-        return false;
+        mPlayer->seek((qint64)value * 1000000);
     }
-
-    mFileName = path;
-
-    this->start(); //启动线程
-
-    mPlayerState = Playing;
-
-    return true;
-
 }
 
-bool VideoPlayer::play()
+void VideoPlayer::slotTimerTimeOut()
 {
-    mVideoState.isPause = false;
-
-    if (mPlayerState != Pause)
+    if (QObject::sender() == mTimer)
     {
-        return false;
-    }
 
-    mPlayerState = Playing;
-    emit sig_StateChanged(Playing);
+        qint64 Sec = mPlayer->getCurrentTime();
 
-    return true;
-}
+        ui->horizontalSlider->setValue(Sec);
 
-bool VideoPlayer::pause()
-{
-    mVideoState.isPause = true;
+    //    QString hStr = QString("00%1").arg(Sec/3600);
+        QString mStr = QString("00%1").arg(Sec/60);
+        QString sStr = QString("00%1").arg(Sec%60);
 
-    if (mPlayerState != Playing)
-    {
-        return false;
+        QString str = QString("%1:%2").arg(mStr.right(2)).arg(sStr.right(2));
+        ui->label_currenttime->setText(str);
     }
-
-    mPlayerState = Pause;
-
-    emit sig_StateChanged(Pause);
-
-    return true;
 }
 
-bool VideoPlayer::stop(bool isWait)
+void VideoPlayer::slotBtnClick()
 {
-    if (mPlayerState == Stop)
+    if (QObject::sender() == ui->pushButton_play)
     {
-        return false;
+        mPlayer->play();
     }
-
-    mVideoState.quit = 1;
-
-    if (isWait)
+    else if (QObject::sender() == ui->pushButton_pause)
     {
-        while(!mVideoState.readThreadFinished || !mVideoState.videoThreadFinished)
-        {
-            SDL_Delay(10);
-        }
+        mPlayer->pause();
     }
-
-    ///关闭SDL音频播放设备
-    if (mVideoState.audioID != 0)
+    else if (QObject::sender() == ui->pushButton_stop)
     {
-        SDL_LockAudio();
-        SDL_PauseAudioDevice(mVideoState.audioID,1);
-        SDL_UnlockAudio();
-
-        mVideoState.audioID = 0;
+        mPlayer->stop(true);
     }
-
-    mPlayerState = Stop;
-    emit sig_StateChanged(Stop);
-
-    return true;
-}
-
-void VideoPlayer::seek(int64_t pos)
-{
-    if(!mVideoState.seek_req)
+    else if (QObject::sender() == ui->pushButton_open || QObject::sender() == ui->toolButton_open)
     {
-        mVideoState.seek_pos = pos;
-        mVideoState.seek_req = 1;
-    }
-}
-
-double VideoPlayer::getCurrentTime()
-{
-    return mVideoState.audio_clock;
-}
-
-int64_t VideoPlayer::getTotalTime()
-{
-    return mVideoState.ic->duration;
-}
-
-void VideoPlayer::disPlayVideo(QImage img)
-{
-    emit sig_GetOneFrame(img);  //发送信号
-}
-
-void VideoPlayer::run()
-{
-    char file_path[1280] = {0};;
-
-    strcpy(file_path,mFileName.toUtf8().data());
-
-    memset(&mVideoState,0,sizeof(VideoState)); //为了安全起见  先将结构体的数据初始化成0了
-
-    VideoState *is = &mVideoState;
-
-    AVFormatContext *pFormatCtx;
-    AVCodecContext *pCodecCtx;
-    AVCodec *pCodec;
-
-    AVCodecContext *aCodecCtx;
-    AVCodec *aCodec;
-
-    int audioStream ,videoStream, i;
-
-
-    //Allocate an AVFormatContext.
-    pFormatCtx = avformat_alloc_context();
-
-    if (avformat_open_input(&pFormatCtx, file_path, NULL, NULL) != 0) {
-        printf("can't open the file. \n");
-        return;
-    }
-
-    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
-        printf("Could't find stream infomation.\n");
-        return;
-    }
-
-    videoStream = -1;
-    audioStream = -1;
-
-    ///循环查找视频中包含的流信息,
-    for (i = 0; i < pFormatCtx->nb_streams; i++) {
-        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+        QString s = QFileDialog::getOpenFileName(
+                   this, "选择要播放的文件",
+                    "/",//初始目录
+                    "视频文件 (*.flv *.rmvb *.avi *.MP4);; 所有文件 (*.*);; ");
+        if (!s.isEmpty())
         {
-            videoStream = i;
-        }
-        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO  && audioStream < 0)
-        {
-            audioStream = i;
-        }
-    }
+            s.replace("/","\\");
 
-    ///如果videoStream为-1 说明没有找到视频流
-    if (videoStream == -1) {
-        printf("Didn't find a video stream.\n");
-        return;
-    }
-
-    if (audioStream == -1) {
-        printf("Didn't find a audio stream.\n");
-        return;
-    }
+            mPlayer->stop(true); //如果在播放则先停止
 
-    is->ic = pFormatCtx;
-    is->videoStream = videoStream;
-    is->audioStream = audioStream;
+            mPlayer->setFileName(s);
 
-    emit sig_TotalTimeChanged(getTotalTime());
+            mTimer->start();
 
-    if (audioStream >= 0) {
-        /* 所有设置SDL音频流信息的步骤都在这个函数里完成 */
-        audio_stream_component_open(&mVideoState, audioStream);
-    }
-
-    ///查找音频解码器
-    aCodecCtx = pFormatCtx->streams[audioStream]->codec;
-    aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
-
-    if (aCodec == NULL) {
-        printf("ACodec not found.\n");
-        return;
-    }
-
-    ///打开音频解码器
-    if (avcodec_open2(aCodecCtx, aCodec, NULL) < 0) {
-        printf("Could not open audio codec.\n");
-        return;
+        }
     }
 
-    is->audio_st = pFormatCtx->streams[audioStream];
-
-    ///查找视频解码器
-    pCodecCtx = pFormatCtx->streams[videoStream]->codec;
-    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
+}
 
-    if (pCodec == NULL) {
-        printf("PCodec not found.\n");
-        return;
-    }
+void VideoPlayer::slotStateChanged(VideoPlayer_Thread::PlayerState state)
+{
 
-    ///打开视频解码器
-    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
-        printf("Could not open video codec.\n");
-        return;
+    if (state == VideoPlayer_Thread::Stop)
+    {
+        ui->widget_video->hide();
+        ui->widget_showopen->show();
+        ui->pushButton_pause->hide();
     }
-
-    is->video_st = pFormatCtx->streams[videoStream];
-    packet_queue_init(&is->videoq);
-
-    ///创建一个线程专门用来解码视频
-    is->video_tid = SDL_CreateThread(video_thread, "video_thread", &mVideoState);
-
-
-    is->player = this;
-
-//    int y_size = pCodecCtx->width * pCodecCtx->height;
-
-    AVPacket *packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packet 用来存放读取的视频
-//    av_new_packet(packet, y_size); //av_read_frame 会给它分配空间 因此这里不需要了
-
-    av_dump_format(pFormatCtx, 0, file_path, 0); //输出视频信息
-
-    while (1)
+    else if (state == VideoPlayer_Thread::Playing)
     {
-        if (is->quit) { //停止播放了
-            break;
-        }
-
-        if (is->seek_req)
-        {
-            int stream_index = -1;
-            int64_t seek_target = is->seek_pos;
-
-            if (is->videoStream >= 0)
-                stream_index = is->videoStream;
-            else if (is->audioStream >= 0)
-                stream_index = is->audioStream;
-
-            AVRational aVRational = {1, AV_TIME_BASE};
-            if (stream_index >= 0) {
-                seek_target = av_rescale_q(seek_target, aVRational,
-                        pFormatCtx->streams[stream_index]->time_base);
-            }
-
-            if (av_seek_frame(is->ic, stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) {
-                fprintf(stderr, "%s: error while seeking\n",is->ic->filename);
-            } else {
-                if (is->audioStream >= 0) {
-                    AVPacket *packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packet
-                    av_new_packet(packet, 10);
-                    strcpy((char*)packet->data,FLUSH_DATA);
-                    packet_queue_flush(&is->audioq); //清除队列
-                    packet_queue_put(&is->audioq, packet); //往队列中存入用来清除的包
-                }
-                if (is->videoStream >= 0) {
-                    AVPacket *packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packet
-                    av_new_packet(packet, 10);
-                    strcpy((char*)packet->data,FLUSH_DATA);
-                    packet_queue_flush(&is->videoq); //清除队列
-                    packet_queue_put(&is->videoq, packet); //往队列中存入用来清除的包
-                    is->video_clock = 0;
-                }
-            }
-            is->seek_req = 0;
-            is->seek_time = is->seek_pos / 1000000.0;
-            is->seek_flag_audio = 1;
-            is->seek_flag_video = 1;
-        }
-
-        //这里做了个限制  当队列里面的数据超过某个大小的时候 就暂停读取  防止一下子就把视频读完了,导致的空间分配不足
-        /* 这里audioq.size是指队列中的所有数据包带的音频数据的总量或者视频数据总量,并不是包的数量 */
-        //这个值可以稍微写大一些
-        if (is->audioq.size > MAX_AUDIO_SIZE || is->videoq.size > MAX_VIDEO_SIZE) {
-            SDL_Delay(10);
-            continue;
-        }
-
-        if (is->isPause == true)
-        {
-            SDL_Delay(10);
-            continue;
-        }
-
-        if (av_read_frame(pFormatCtx, packet) < 0)
-        {
-            is->readFinished = true;
-
-            if (is->quit)
-            {
-                break; //解码线程也执行完了 可以退出了
-            }
+        ui->widget_showopen->hide();
+        ui->widget_video->show();
 
-            SDL_Delay(10);
-            continue;
-        }
-
-        if (packet->stream_index == videoStream)
-        {
-            packet_queue_put(&is->videoq, packet);
-            //这里我们将数据存入队列 因此不调用 av_free_packet 释放
-        }
-        else if( packet->stream_index == audioStream )
-        {
-            packet_queue_put(&is->audioq, packet);
-            //这里我们将数据存入队列 因此不调用 av_free_packet 释放
-        }
-        else
-        {
-            // Free the packet that was allocated by av_read_frame
-            av_free_packet(packet);
-        }
+        ui->pushButton_play->hide();
+        ui->pushButton_pause->show();
     }
-
-    ///文件读取结束 跳出循环的情况
-    ///等待播放完毕
-    while (!is->quit) {
-        SDL_Delay(100);
+    else if (state == VideoPlayer_Thread::Pause)
+    {
+        ui->pushButton_pause->hide();
+        ui->pushButton_play->show();
     }
-
-    stop();
-
-    avcodec_close(pCodecCtx);
-    avformat_close_input(&pFormatCtx);
-
-    is->readThreadFinished = true;
-
 }
+

+ 26 - 114
src/videoplayer/videoplayer.h

@@ -7,137 +7,49 @@
 #ifndef VIDEOPLAYER_H
 #define VIDEOPLAYER_H
 
-#include <QThread>
+#include <QWidget>
+#include <customtitle.h>
+
 #include <QImage>
+#include <QPaintEvent>
+#include <QTimer>
+#include <QPushButton>
 
-extern "C"
-{
-    #include "libavcodec/avcodec.h"
-    #include "libavformat/avformat.h"
-    #include <libavutil/time.h>
-    #include "libavutil/pixfmt.h"
-    #include "libswscale/swscale.h"
-    #include "libswresample/swresample.h"
+#include "videoplayer/videoplayer_thread.h"
 
-    #include <SDL.h>
-    #include <SDL_audio.h>
-    #include <SDL_types.h>
-    #include <SDL_name.h>
-    #include <SDL_main.h>
-    #include <SDL_config.h>
+namespace Ui {
+class VideoPlayer;
 }
 
-typedef struct PacketQueue {
-    AVPacketList *first_pkt, *last_pkt;
-    int nb_packets;
-    int size;
-    SDL_mutex *mutex;
-    SDL_cond *cond;
-} PacketQueue;
-
-#define VIDEO_PICTURE_QUEUE_SIZE 1
-#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
-
-#define MAX_AUDIO_SIZE (25 * 16 * 1024)
-#define MAX_VIDEO_SIZE (25 * 256 * 1024)
-
-class VideoPlayer; //前置声明
-
-typedef struct VideoState {
-    AVFormatContext *ic;
-    int videoStream, audioStream;
-    AVFrame *audio_frame;// 解码音频过程中的使用缓存
-    PacketQueue audioq;
-    AVStream *audio_st; //音频流
-    unsigned int audio_buf_size;
-    unsigned int audio_buf_index;
-    AVPacket audio_pkt;
-    uint8_t *audio_pkt_data;
-    int audio_pkt_size;
-    uint8_t *audio_buf;
-    DECLARE_ALIGNED(16,uint8_t,audio_buf2) [AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
-    enum AVSampleFormat audio_src_fmt;
-    enum AVSampleFormat audio_tgt_fmt;
-    int audio_src_channels;
-    int audio_tgt_channels;
-    int64_t audio_src_channel_layout;
-    int64_t audio_tgt_channel_layout;
-    int audio_src_freq;
-    int audio_tgt_freq;
-    struct SwrContext *swr_ctx; //用于解码后的音频格式转换
-    int audio_hw_buf_size;
-
-    double audio_clock; ///音频时钟
-    double video_clock; ///<pts of last decoded frame / predicted pts of next decoded frame
-
-    AVStream *video_st;
-    PacketQueue videoq;
-
-    /// 跳转相关的变量
-    int             seek_req; //跳转标志
-    int64_t         seek_pos; //跳转的位置 -- 微秒
-    int             seek_flag_audio;//跳转标志 -- 用于音频线程中
-    int             seek_flag_video;//跳转标志 -- 用于视频线程中
-    double          seek_time; //跳转的时间(秒)  值和seek_pos是一样的
-
-    ///播放控制相关
-    bool isPause;  //暂停标志
-    bool quit;  //停止
-    bool readFinished; //文件读取完毕
-    bool readThreadFinished;
-    bool videoThreadFinished;
-
-    SDL_Thread *video_tid;  //视频线程id
-    SDL_AudioDeviceID audioID;
-
-    VideoPlayer *player; //记录下这个类的指针  主要用于在线程里面调用激发信号的函数
+///这个是播放器的主界面 包括那些按钮和进度条之类的
 
-} VideoState;
-
-class VideoPlayer : public QThread
+class VideoPlayer : public CustomTitle
 {
     Q_OBJECT
 
 public:
-
-    enum PlayerState
-    {
-        Playing,
-        Pause,
-        Stop
-    };
-
-    explicit VideoPlayer();
+    explicit VideoPlayer(QWidget *parent = 0);
     ~VideoPlayer();
 
-    bool setFileName(QString path);
-
-    bool play();
-    bool pause();
-    bool stop(bool isWait = false); //参数表示是否等待所有的线程执行完毕再返回
-
-    void seek(int64_t pos); //单位是微秒
-
-    int64_t getTotalTime(); //单位微秒
-    double getCurrentTime(); //单位秒
-
-    void disPlayVideo(QImage img);
-
-signals:
-    void sig_GetOneFrame(QImage); //没获取到一帧图像 就发送此信号
-
-    void sig_StateChanged(VideoPlayer::PlayerState state);
-    void sig_TotalTimeChanged(qint64 uSec); //获取到视频时长的时候激发此信号
-
 protected:
-    void run();
+    void doClose();
+//    void mousePressEvent(QMouseEvent *e);
+//    void mouseDoubleClickEvent(QMouseEvent *);
 
 private:
-    QString mFileName;
+    Ui::VideoPlayer *ui;
+
+    VideoPlayer_Thread *mPlayer; //播放线程
+    QTimer *mTimer; //定时器-获取当前视频时间
 
-    VideoState mVideoState;
+private slots:
+    ///播放器相关的槽函数
+    void slotTotalTimeChanged(qint64 uSec);
+    void slotSliderMoved(int value);
+    void slotTimerTimeOut();
+    void slotBtnClick();
 
-    PlayerState mPlayerState; //播放状态
+    void slotStateChanged(VideoPlayer_Thread::PlayerState state);
 
 };
 

+ 438 - 0
src/videoplayer/videoplayer.ui

@@ -0,0 +1,438 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VideoPlayer</class>
+ <widget class="QWidget" name="VideoPlayer">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1060</width>
+    <height>695</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widget_container" native="true">
+     <property name="styleSheet">
+      <string notr="true">QWidget#widget_container
+{
+	background-color: rgb(22, 22, 22);
+	border:1px solid rgba(0, 0, 0, 30);
+	border-radius:2px;  /*边框拐角*/
+}
+</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_3">
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_6">
+        <property name="spacing">
+         <number>0</number>
+        </property>
+        <property name="rightMargin">
+         <number>0</number>
+        </property>
+        <property name="bottomMargin">
+         <number>0</number>
+        </property>
+        <item>
+         <layout class="QVBoxLayout" name="verticalLayout_4">
+          <property name="spacing">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QWidget" name="widget_showopen" native="true">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">QWidget#widget_showopen
+{
+	
+	background-color: rgba(60, 65, 68,100);
+}</string>
+            </property>
+            <layout class="QVBoxLayout" name="verticalLayout_5">
+             <item>
+              <layout class="QHBoxLayout" name="horizontalLayout_3">
+               <item>
+                <spacer name="horizontalSpacer">
+                 <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                 </property>
+                 <property name="sizeHint" stdset="0">
+                  <size>
+                   <width>40</width>
+                   <height>20</height>
+                  </size>
+                 </property>
+                </spacer>
+               </item>
+               <item>
+                <widget class="QToolButton" name="toolButton_open">
+                 <property name="minimumSize">
+                  <size>
+                   <width>160</width>
+                   <height>50</height>
+                  </size>
+                 </property>
+                 <property name="text">
+                  <string>打开文件</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <spacer name="horizontalSpacer_2">
+                 <property name="orientation">
+                  <enum>Qt::Horizontal</enum>
+                 </property>
+                 <property name="sizeHint" stdset="0">
+                  <size>
+                   <width>40</width>
+                   <height>20</height>
+                  </size>
+                 </property>
+                </spacer>
+               </item>
+              </layout>
+             </item>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <widget class="QWidget" name="widget_video" native="true">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="styleSheet">
+             <string notr="true"/>
+            </property>
+            <layout class="QVBoxLayout" name="verticalLayout_2">
+             <property name="spacing">
+              <number>0</number>
+             </property>
+             <property name="margin">
+              <number>0</number>
+             </property>
+             <item>
+              <layout class="QVBoxLayout" name="verticalLayout_show_video"/>
+             </item>
+            </layout>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <widget class="QWidget" name="widget_right" native="true">
+          <property name="minimumSize">
+           <size>
+            <width>200</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>200</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="styleSheet">
+           <string notr="true">background-color: rgb(0, 255, 255);</string>
+          </property>
+          <layout class="QVBoxLayout" name="verticalLayout_6">
+           <item>
+            <widget class="QListWidget" name="listWidget">
+             <item>
+              <property name="text">
+               <string>新建项目</string>
+              </property>
+             </item>
+             <item>
+              <property name="text">
+               <string>新建项目</string>
+              </property>
+             </item>
+             <item>
+              <property name="text">
+               <string>新建项目</string>
+              </property>
+             </item>
+             <item>
+              <property name="text">
+               <string>新建项目</string>
+              </property>
+             </item>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <widget class="QWidget" name="widget_controller" native="true">
+        <property name="minimumSize">
+         <size>
+          <width>0</width>
+          <height>60</height>
+         </size>
+        </property>
+        <property name="styleSheet">
+         <string notr="true">QWidget#widget_controller
+{
+	background-color: rgba(60, 65, 68,100);
+}</string>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_7">
+         <item>
+          <layout class="QHBoxLayout" name="horizontalLayout_2">
+           <item>
+            <widget class="VideoSlider" name="horizontalSlider">
+             <property name="cursor">
+              <cursorShape>PointingHandCursor</cursorShape>
+             </property>
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <layout class="QHBoxLayout" name="horizontalLayout">
+             <item>
+              <widget class="QLabel" name="label_currenttime">
+               <property name="styleSheet">
+                <string notr="true">QLabel{
+	border-radius:0px;
+	color: #F0F0F0;
+	background-color:rgba(0,0,0,0);
+	border-style:none;
+font: 10pt &quot;微软雅黑&quot;;
+font-size:20px;
+font-weight:bold;
+}
+</string>
+               </property>
+               <property name="text">
+                <string>00:00:00</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QLabel" name="label_2">
+               <property name="styleSheet">
+                <string notr="true">QLabel{
+	border-radius:0px;
+	color: #F0F0F0;
+	background-color:rgba(0,0,0,0);
+	border-style:none;
+font: 10pt &quot;微软雅黑&quot;;
+font-size:20px;
+font-weight:bold;
+}
+</string>
+               </property>
+               <property name="text">
+                <string>/</string>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QLabel" name="label_totaltime">
+               <property name="styleSheet">
+                <string notr="true">QLabel{
+	border-radius:0px;
+	color: #F0F0F0;
+	background-color:rgba(0,0,0,0);
+	border-style:none;
+font: 10pt &quot;微软雅黑&quot;;
+font-size:20px;
+font-weight:bold;
+}
+</string>
+               </property>
+               <property name="text">
+                <string>00:00:00</string>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </item>
+          </layout>
+         </item>
+         <item>
+          <layout class="QHBoxLayout" name="horizontalLayout_4">
+           <item>
+            <widget class="QPushButton" name="pushButton_open">
+             <property name="minimumSize">
+              <size>
+               <width>36</width>
+               <height>36</height>
+              </size>
+             </property>
+             <property name="cursor">
+              <cursorShape>PointingHandCursor</cursorShape>
+             </property>
+             <property name="styleSheet">
+              <string notr="true">QPushButton{ 
+image: url(:image/open_normal.png);
+border-radius:0px; 
+} 
+QPushButton:hover{ 
+image: url(:image/open_focus.png);
+border-radius:0px; 
+} 
+QPushButton:pressed{ 
+image: url(:image/open_normal.png);
+border-radius:0px; 
+}
+</string>
+             </property>
+             <property name="text">
+              <string/>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <spacer name="horizontalSpacer_3">
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>40</width>
+               <height>20</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+           <item>
+            <widget class="QPushButton" name="pushButton_play">
+             <property name="minimumSize">
+              <size>
+               <width>50</width>
+               <height>50</height>
+              </size>
+             </property>
+             <property name="cursor">
+              <cursorShape>PointingHandCursor</cursorShape>
+             </property>
+             <property name="styleSheet">
+              <string notr="true">QPushButton{ 
+image: url(:image/start_normal.png);
+border-radius:0px; 
+}  
+QPushButton:hover{ 
+image: url(:image/start_focus.png);
+border-radius:0px; 
+} 
+QPushButton:pressed{ 
+image: url(:image/start_normal.png);
+border-radius:0px; 
+}
+</string>
+             </property>
+             <property name="text">
+              <string/>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QPushButton" name="pushButton_pause">
+             <property name="minimumSize">
+              <size>
+               <width>50</width>
+               <height>50</height>
+              </size>
+             </property>
+             <property name="cursor">
+              <cursorShape>PointingHandCursor</cursorShape>
+             </property>
+             <property name="styleSheet">
+              <string notr="true">QPushButton{ 
+image: url(:image/pause_normal.png);
+border-radius:0px; 
+} 
+QPushButton:hover{ 
+image: url(:image/pause_focus.png);
+border-radius:0px; 
+} 
+QPushButton:pressed{ 
+image: url(:image/pause_normal.png);
+border-radius:0px; 
+}
+</string>
+             </property>
+             <property name="text">
+              <string/>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QPushButton" name="pushButton_stop">
+             <property name="cursor">
+              <cursorShape>PointingHandCursor</cursorShape>
+             </property>
+             <property name="text">
+              <string>停止</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <spacer name="horizontalSpacer_4">
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>40</width>
+               <height>20</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </item>
+        </layout>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>VideoSlider</class>
+   <extends>QSlider</extends>
+   <header>src\videoplayer\widget\videoslider.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>

+ 50 - 0
src/videoplayer/videoplayer_showvideowidget.cpp

@@ -0,0 +1,50 @@
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#include "videoplayer_showvideowidget.h"
+#include "ui_videoplayer_showvideowidget.h"
+
+#include <QPainter>
+
+VideoPlayer_ShowVideoWidget::VideoPlayer_ShowVideoWidget(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::VideoPlayer_ShowVideoWidget)
+{
+    ui->setupUi(this);
+}
+
+VideoPlayer_ShowVideoWidget::~VideoPlayer_ShowVideoWidget()
+{
+    delete ui;
+}
+
+void VideoPlayer_ShowVideoWidget::paintEvent(QPaintEvent *event)
+{
+    QPainter painter(this);
+    painter.setBrush(Qt::black);
+    painter.drawRect(0,0,this->width(),this->height()); //先画成黑色
+
+
+    if (mImage.size().width() <= 0) return;
+
+    ///将图像按比例缩放成和窗口一样大小
+    QImage img = mImage.scaled(this->size(),Qt::KeepAspectRatio);
+
+    int x = this->width() - img.width();
+    int y = this->height() - img.height();
+
+    x /= 2;
+    y /= 2;
+
+    painter.drawImage(QPoint(x,y),img); //画出图像
+
+}
+
+void VideoPlayer_ShowVideoWidget::slotGetOneFrame(QImage img)
+{
+    mImage = img;
+    update(); //调用update将执行 paintEvent函数
+}

+ 43 - 0
src/videoplayer/videoplayer_showvideowidget.h

@@ -0,0 +1,43 @@
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#ifndef VIDEOPLAYER_SHOWVIDEOWIDGET_H
+#define VIDEOPLAYER_SHOWVIDEOWIDGET_H
+
+#include <QWidget>
+#include <QPaintEvent>
+
+namespace Ui {
+class VideoPlayer_ShowVideoWidget;
+}
+
+
+///显示视频用的widget
+///这个仅仅是显示视频画面的控件
+
+class VideoPlayer_ShowVideoWidget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit VideoPlayer_ShowVideoWidget(QWidget *parent = 0);
+    ~VideoPlayer_ShowVideoWidget();
+
+protected:
+    void paintEvent(QPaintEvent *event);
+
+    QImage mImage; //记录当前的图像
+
+private:
+    Ui::VideoPlayer_ShowVideoWidget *ui;
+
+public slots:
+    ///播放器相关的槽函数
+    void slotGetOneFrame(QImage img);
+
+};
+
+#endif // VIDEOPLAYER_SHOWVIDEOWIDGET_H

+ 21 - 0
src/videoplayer/videoplayer_showvideowidget.ui

@@ -0,0 +1,21 @@
+<ui version="4.0">
+ <author/>
+ <comment/>
+ <exportmacro/>
+ <class>VideoPlayer_ShowVideoWidget</class>
+ <widget class="QWidget" name="VideoPlayer_ShowVideoWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+ </widget>
+ <pixmapfunction/>
+ <connections/>
+</ui>

+ 1022 - 0
src/videoplayer/videoplayer_thread.cpp

@@ -0,0 +1,1022 @@
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#include "videoplayer_thread.h"
+
+#include <stdio.h>
+
+#include <QDebug>
+
+#define SDL_AUDIO_BUFFER_SIZE 1024
+#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
+
+#define FLUSH_DATA "FLUSH"
+
+void packet_queue_init(PacketQueue *q) {
+    memset(q, 0, sizeof(PacketQueue));
+    q->mutex = SDL_CreateMutex();
+    q->cond = SDL_CreateCond();
+    q->size = 0;
+    q->nb_packets = 0;
+    q->first_pkt = NULL;
+    q->last_pkt = NULL;
+}
+
+int packet_queue_put(PacketQueue *q, AVPacket *pkt) {
+
+    AVPacketList *pkt1;
+    if (av_dup_packet(pkt) < 0) {
+        return -1;
+    }
+    pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList));
+    if (!pkt1)
+        return -1;
+    pkt1->pkt = *pkt;
+    pkt1->next = NULL;
+
+    SDL_LockMutex(q->mutex);
+
+    if (!q->last_pkt)
+        q->first_pkt = pkt1;
+    else
+        q->last_pkt->next = pkt1;
+    q->last_pkt = pkt1;
+    q->nb_packets++;
+    q->size += pkt1->pkt.size;
+    SDL_CondSignal(q->cond);
+
+    SDL_UnlockMutex(q->mutex);
+    return 0;
+}
+
+static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) {
+    AVPacketList *pkt1;
+    int ret;
+
+    SDL_LockMutex(q->mutex);
+
+    for (;;) {
+
+        pkt1 = q->first_pkt;
+        if (pkt1) {
+            q->first_pkt = pkt1->next;
+            if (!q->first_pkt)
+                q->last_pkt = NULL;
+            q->nb_packets--;
+            q->size -= pkt1->pkt.size;
+            *pkt = pkt1->pkt;
+            av_free(pkt1);
+            ret = 1;
+            break;
+        } else if (!block) {
+            ret = 0;
+            break;
+        } else {
+            SDL_CondWait(q->cond, q->mutex);
+        }
+
+    }
+
+    SDL_UnlockMutex(q->mutex);
+    return ret;
+}
+
+static void packet_queue_flush(PacketQueue *q)
+{
+    AVPacketList *pkt, *pkt1;
+
+    SDL_LockMutex(q->mutex);
+    for(pkt = q->first_pkt; pkt != NULL; pkt = pkt1)
+    {
+        pkt1 = pkt->next;
+
+        if(pkt1->pkt.data != (uint8_t *)"FLUSH")
+        {
+
+        }
+        av_free_packet(&pkt->pkt);
+        av_freep(&pkt);
+
+    }
+    q->last_pkt = NULL;
+    q->first_pkt = NULL;
+    q->nb_packets = 0;
+    q->size = 0;
+    SDL_UnlockMutex(q->mutex);
+}
+
+static int audio_decode_frame(VideoState *is, double *pts_ptr)
+{
+    int len1, len2, decoded_data_size;
+    AVPacket *pkt = &is->audio_pkt;
+    int got_frame = 0;
+    int64_t dec_channel_layout;
+    int wanted_nb_samples, resampled_data_size, n;
+
+    double pts;
+
+    for (;;) {
+
+        while (is->audio_pkt_size > 0) {
+
+            if (is->isPause == true) //判断暂停
+            {
+                SDL_Delay(10);
+                continue;
+            }
+
+            if (!is->audio_frame) {
+                if (!(is->audio_frame = avcodec_alloc_frame())) {
+                    return AVERROR(ENOMEM);
+                }
+            } else
+                avcodec_get_frame_defaults(is->audio_frame);
+
+            len1 = avcodec_decode_audio4(is->audio_st->codec, is->audio_frame,
+                    &got_frame, pkt);
+            if (len1 < 0) {
+                // error, skip the frame
+                is->audio_pkt_size = 0;
+                break;
+            }
+
+            is->audio_pkt_data += len1;
+            is->audio_pkt_size -= len1;
+
+            if (!got_frame)
+                continue;
+
+            /* 计算解码出来的桢需要的缓冲大小 */
+            decoded_data_size = av_samples_get_buffer_size(NULL,
+                    is->audio_frame->channels, is->audio_frame->nb_samples,
+                    (AVSampleFormat)is->audio_frame->format, 1);
+
+            dec_channel_layout =
+                    (is->audio_frame->channel_layout
+                            && is->audio_frame->channels
+                                    == av_get_channel_layout_nb_channels(
+                                            is->audio_frame->channel_layout)) ?
+                            is->audio_frame->channel_layout :
+                            av_get_default_channel_layout(
+                                    is->audio_frame->channels);
+
+            wanted_nb_samples = is->audio_frame->nb_samples;
+
+            if (is->audio_frame->format != is->audio_src_fmt
+                    || dec_channel_layout != is->audio_src_channel_layout
+                    || is->audio_frame->sample_rate != is->audio_src_freq
+                    || (wanted_nb_samples != is->audio_frame->nb_samples
+                            && !is->swr_ctx)) {
+                if (is->swr_ctx)
+                    swr_free(&is->swr_ctx);
+                is->swr_ctx = swr_alloc_set_opts(NULL,
+                        is->audio_tgt_channel_layout, (AVSampleFormat)is->audio_tgt_fmt,
+                        is->audio_tgt_freq, dec_channel_layout,
+                        (AVSampleFormat)is->audio_frame->format, is->audio_frame->sample_rate,
+                        0, NULL);
+                if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {
+                    //fprintf(stderr,"swr_init() failed\n");
+                    break;
+                }
+                is->audio_src_channel_layout = dec_channel_layout;
+                is->audio_src_channels = is->audio_st->codec->channels;
+                is->audio_src_freq = is->audio_st->codec->sample_rate;
+                is->audio_src_fmt = is->audio_st->codec->sample_fmt;
+            }
+
+            /* 这里我们可以对采样数进行调整,增加或者减少,一般可以用来做声画同步 */
+            if (is->swr_ctx) {
+                const uint8_t **in =
+                        (const uint8_t **) is->audio_frame->extended_data;
+                uint8_t *out[] = { is->audio_buf2 };
+                if (wanted_nb_samples != is->audio_frame->nb_samples) {
+                    if (swr_set_compensation(is->swr_ctx,
+                            (wanted_nb_samples - is->audio_frame->nb_samples)
+                                    * is->audio_tgt_freq
+                                    / is->audio_frame->sample_rate,
+                            wanted_nb_samples * is->audio_tgt_freq
+                                    / is->audio_frame->sample_rate) < 0) {
+                        //fprintf(stderr,"swr_set_compensation() failed\n");
+                        break;
+                    }
+                }
+
+                len2 = swr_convert(is->swr_ctx, out,
+                        sizeof(is->audio_buf2) / is->audio_tgt_channels
+                                / av_get_bytes_per_sample(is->audio_tgt_fmt),
+                        in, is->audio_frame->nb_samples);
+                if (len2 < 0) {
+                    //fprintf(stderr,"swr_convert() failed\n");
+                    break;
+                }
+                if (len2
+                        == sizeof(is->audio_buf2) / is->audio_tgt_channels
+                                / av_get_bytes_per_sample(is->audio_tgt_fmt)) {
+                    //fprintf(stderr,"warning: audio buffer is probably too small\n");
+                    swr_init(is->swr_ctx);
+                }
+                is->audio_buf = is->audio_buf2;
+                resampled_data_size = len2 * is->audio_tgt_channels
+                        * av_get_bytes_per_sample(is->audio_tgt_fmt);
+            } else {
+                resampled_data_size = decoded_data_size;
+                is->audio_buf = is->audio_frame->data[0];
+            }
+
+            pts = is->audio_clock;
+            *pts_ptr = pts;
+            n = 2 * is->audio_st->codec->channels;
+            is->audio_clock += (double) resampled_data_size
+                    / (double) (n * is->audio_st->codec->sample_rate);
+
+
+            if (is->seek_flag_audio)
+            {
+                //发生了跳转 则跳过关键帧到目的时间的这几帧
+               if (is->audio_clock < is->seek_time)
+               {
+                   break;
+               }
+               else
+               {
+                   is->seek_flag_audio = 0;
+               }
+            }
+
+
+            // We have data, return it and come back for more later
+            return resampled_data_size;
+        }
+
+        if (pkt->data)
+            av_free_packet(pkt);
+        memset(pkt, 0, sizeof(*pkt));
+
+        if (is->quit)
+            return -1;
+
+        if (is->isPause == true) //判断暂停
+        {
+            SDL_Delay(10);
+            continue;
+        }
+
+        if (packet_queue_get(&is->audioq, pkt, 0) <= 0)
+        {
+            return -1;
+        }
+
+        //收到这个数据 说明刚刚执行过跳转 现在需要把解码器的数据 清除一下
+        if(strcmp((char*)pkt->data,FLUSH_DATA) == 0)
+        {
+            avcodec_flush_buffers(is->audio_st->codec);
+            av_free_packet(pkt);
+            continue;
+        }
+
+        is->audio_pkt_data = pkt->data;
+        is->audio_pkt_size = pkt->size;
+
+        /* if update, update the audio clock w/pts */
+        if (pkt->pts != AV_NOPTS_VALUE) {
+            is->audio_clock = av_q2d(is->audio_st->time_base) * pkt->pts;
+        }
+    }
+
+    return 0;
+}
+
+
+static void audio_callback(void *userdata, Uint8 *stream, int len) {
+    VideoState *is = (VideoState *) userdata;
+
+    int len1, audio_data_size;
+
+    double pts;
+
+    /*   len是由SDL传入的SDL缓冲区的大小,如果这个缓冲未满,我们就一直往里填充数据 */
+    while (len > 0) {
+        /*  audio_buf_index 和 audio_buf_size 标示我们自己用来放置解码出来的数据的缓冲区,*/
+        /*   这些数据待copy到SDL缓冲区, 当audio_buf_index >= audio_buf_size的时候意味着我*/
+        /*   们的缓冲为空,没有数据可供copy,这时候需要调用audio_decode_frame来解码出更
+         /*   多的桢数据 */
+        if (is->audio_buf_index >= is->audio_buf_size) {
+
+            audio_data_size = audio_decode_frame(is, &pts);
+
+            /* audio_data_size < 0 标示没能解码出数据,我们默认播放静音 */
+            if (audio_data_size < 0) {
+                /* silence */
+                is->audio_buf_size = 1024;
+                /* 清零,静音 */
+                if (is->audio_buf == NULL) return;
+                memset(is->audio_buf, 0, is->audio_buf_size);
+            } else {
+                is->audio_buf_size = audio_data_size;
+            }
+            is->audio_buf_index = 0;
+        }
+        /*  查看stream可用空间,决定一次copy多少数据,剩下的下次继续copy */
+        len1 = is->audio_buf_size - is->audio_buf_index;
+        if (len1 > len) {
+            len1 = len;
+        }
+
+        if (is->audio_buf == NULL) return;
+
+        memcpy(stream, (uint8_t *) is->audio_buf + is->audio_buf_index, len1);
+//        SDL_MixAudio(stream, (uint8_t * )is->audio_buf + is->audio_buf_index, len1, 50);
+
+//        SDL_MixAudioFormat(stream, (uint8_t * )is->audio_buf + is->audio_buf_index, AUDIO_S16SYS, len1, 50);
+
+        len -= len1;
+        stream += len1;
+        is->audio_buf_index += len1;
+    }
+
+}
+
+static double get_audio_clock(VideoState *is)
+{
+    double pts;
+    int hw_buf_size, bytes_per_sec, n;
+
+    pts = is->audio_clock; /* maintained in the audio thread */
+    hw_buf_size = is->audio_buf_size - is->audio_buf_index;
+    bytes_per_sec = 0;
+    n = is->audio_st->codec->channels * 2;
+    if(is->audio_st)
+    {
+        bytes_per_sec = is->audio_st->codec->sample_rate * n;
+    }
+    if(bytes_per_sec)
+    {
+        pts -= (double)hw_buf_size / bytes_per_sec;
+    }
+    return pts;
+}
+
+static double synchronize_video(VideoState *is, AVFrame *src_frame, double pts) {
+
+    double frame_delay;
+
+    if (pts != 0) {
+        /* if we have pts, set video clock to it */
+        is->video_clock = pts;
+    } else {
+        /* if we aren't given a pts, set it to the clock */
+        pts = is->video_clock;
+    }
+    /* update the video clock */
+    frame_delay = av_q2d(is->video_st->codec->time_base);
+    /* if we are repeating a frame, adjust clock accordingly */
+    frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
+    is->video_clock += frame_delay;
+    return pts;
+}
+
+int audio_stream_component_open(VideoState *is, int stream_index)
+{
+    AVFormatContext *ic = is->ic;
+    AVCodecContext *codecCtx;
+    AVCodec *codec;
+    SDL_AudioSpec wanted_spec, spec;
+    int64_t wanted_channel_layout = 0;
+    int wanted_nb_channels;
+    /*  SDL支持的声道数为 1, 2, 4, 6 */
+    /*  后面我们会使用这个数组来纠正不支持的声道数目 */
+    const int next_nb_channels[] = { 0, 0, 1, 6, 2, 6, 4, 6 };
+
+    if (stream_index < 0 || stream_index >= ic->nb_streams) {
+        return -1;
+    }
+
+    codecCtx = ic->streams[stream_index]->codec;
+    wanted_nb_channels = codecCtx->channels;
+    if (!wanted_channel_layout
+            || wanted_nb_channels
+                    != av_get_channel_layout_nb_channels(
+                            wanted_channel_layout)) {
+        wanted_channel_layout = av_get_default_channel_layout(
+                wanted_nb_channels);
+        wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
+    }
+
+    wanted_spec.channels = av_get_channel_layout_nb_channels(
+            wanted_channel_layout);
+    wanted_spec.freq = codecCtx->sample_rate;
+    if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
+        //fprintf(stderr,"Invalid sample rate or channel count!\n");
+        return -1;
+    }
+    wanted_spec.format = AUDIO_S16SYS; // 具体含义请查看“SDL宏定义”部分
+    wanted_spec.silence = 0;            // 0指示静音
+    wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;  // 自定义SDL缓冲区大小
+    wanted_spec.callback = audio_callback;        // 音频解码的关键回调函数
+    wanted_spec.userdata = is;                    // 传给上面回调函数的外带数据
+
+//    SDL_AudioDeviceID audioID = 1;// = SDL_OpenAudioDevice("",0,&wanted_spec, &spec,1);
+//    int num = SDL_GetNumAudioDevices(0);
+//    for (int i=0;i<num;i++)
+//    {
+//        qDebug()<<SDL_GetAudioDeviceName(i,0);
+//    }
+
+//    ///  打开SDL播放设备 - 开始
+//    SDL_LockAudio();
+//    SDL_AudioSpec spec;
+//    SDL_AudioSpec wanted_spec;
+//    wanted_spec.freq = aCodecCtx->sample_rate;
+//    wanted_spec.format = AUDIO_S16SYS;
+//    wanted_spec.channels = aCodecCtx->channels;
+//    wanted_spec.silence = 0;
+//    wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
+//    wanted_spec.callback = audio_callback;
+//    wanted_spec.userdata = &mVideoState;
+//    if(SDL_OpenAudio(&wanted_spec, &spec) < 0)
+//    {
+//        fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
+//        return;
+//    }
+//    SDL_UnlockAudio();
+//    SDL_PauseAudio(0);
+//    ///  打开SDL播放设备 - 结束
+
+    /*  打开音频设备,这里使用一个while来循环尝试打开不同的声道数(由上面 */
+    /*  next_nb_channels数组指定)直到成功打开,或者全部失败 */
+//    while (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
+    do {
+
+        is->audioID = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(0,0),0,&wanted_spec, &spec,0);
+
+//        qDebug()<<"audioID"<<audioID;
+
+//        if (audioID >= 1) break;
+
+        fprintf(stderr,"SDL_OpenAudio (%d channels): %s\n",wanted_spec.channels, SDL_GetError());
+        qDebug()<<QString("SDL_OpenAudio (%1 channels): %2").arg(wanted_spec.channels).arg(SDL_GetError());
+        wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];
+        if (!wanted_spec.channels) {
+            fprintf(stderr,"No more channel combinations to tyu, audio open failed\n");
+//            return -1;
+            break;
+        }
+        wanted_channel_layout = av_get_default_channel_layout(
+                wanted_spec.channels);
+    }while(is->audioID == 0);
+
+    /* 检查实际使用的配置(保存在spec,由SDL_OpenAudio()填充) */
+    if (spec.format != AUDIO_S16SYS) {
+        fprintf(stderr,"SDL advised audio format %d is not supported!\n",spec.format);
+        return -1;
+    }
+
+    if (spec.channels != wanted_spec.channels) {
+        wanted_channel_layout = av_get_default_channel_layout(spec.channels);
+        if (!wanted_channel_layout) {
+            fprintf(stderr,"SDL advised channel count %d is not supported!\n",spec.channels);
+            return -1;
+        }
+    }
+
+    is->audio_hw_buf_size = spec.size;
+
+    /* 把设置好的参数保存到大结构中 */
+    is->audio_src_fmt = is->audio_tgt_fmt = AV_SAMPLE_FMT_S16;
+    is->audio_src_freq = is->audio_tgt_freq = spec.freq;
+    is->audio_src_channel_layout = is->audio_tgt_channel_layout =
+            wanted_channel_layout;
+    is->audio_src_channels = is->audio_tgt_channels = spec.channels;
+
+    codec = avcodec_find_decoder(codecCtx->codec_id);
+    if (!codec || (avcodec_open2(codecCtx, codec, NULL) < 0)) {
+        fprintf(stderr,"Unsupported codec!\n");
+        return -1;
+    }
+    ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
+    switch (codecCtx->codec_type) {
+    case AVMEDIA_TYPE_AUDIO:
+//        is->audioStream = stream_index;
+        is->audio_st = ic->streams[stream_index];
+        is->audio_buf_size = 0;
+        is->audio_buf_index = 0;
+        memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
+        packet_queue_init(&is->audioq);
+//        SDL_PauseAudio(0); // 开始播放静音
+        SDL_PauseAudioDevice(is->audioID,0);
+        break;
+    default:
+        break;
+    }
+
+    return 0;
+}
+
+int video_thread(void *arg)
+{
+    VideoState *is = (VideoState *) arg;
+    AVPacket pkt1, *packet = &pkt1;
+
+    int ret, got_picture, numBytes;
+
+    double video_pts = 0; //当前视频的pts
+    double audio_pts = 0; //音频pts
+
+
+    ///解码视频相关
+    AVFrame *pFrame, *pFrameRGB;
+    uint8_t *out_buffer_rgb; //解码后的rgb数据
+    struct SwsContext *img_convert_ctx;  //用于解码后的视频格式转换
+
+    AVCodecContext *pCodecCtx = is->video_st->codec; //视频解码器
+
+    pFrame = av_frame_alloc();
+    pFrameRGB = av_frame_alloc();
+
+    ///这里我们改成了 将解码后的YUV数据转换成RGB32
+    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
+            pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
+            PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
+
+    numBytes = avpicture_get_size(PIX_FMT_RGB32, pCodecCtx->width,pCodecCtx->height);
+
+    out_buffer_rgb = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
+    avpicture_fill((AVPicture *) pFrameRGB, out_buffer_rgb, PIX_FMT_RGB32,
+            pCodecCtx->width, pCodecCtx->height);
+
+    while(1)
+    {
+        if (is->quit)
+        {
+            break;
+        }
+
+        if (is->isPause == true) //判断暂停
+        {
+            SDL_Delay(10);
+            continue;
+        }
+
+        if (packet_queue_get(&is->videoq, packet, 0) <= 0)
+        {
+            if (is->readFinished)
+            {//队列里面没有数据了且读取完毕了
+                break;
+            }
+            else
+            {
+                SDL_Delay(1); //队列只是暂时没有数据而已
+                continue;
+            }
+        }
+
+        //收到这个数据 说明刚刚执行过跳转 现在需要把解码器的数据 清除一下
+        if(strcmp((char*)packet->data,FLUSH_DATA) == 0)
+        {
+            avcodec_flush_buffers(is->video_st->codec);
+            av_free_packet(packet);
+            continue;
+        }
+
+        ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,packet);
+
+        if (ret < 0) {
+            qDebug()<<"decode error.\n";
+            av_free_packet(packet);
+            continue;
+        }
+
+        if (packet->dts == AV_NOPTS_VALUE && pFrame->opaque&& *(uint64_t*) pFrame->opaque != AV_NOPTS_VALUE)
+        {
+            video_pts = *(uint64_t *) pFrame->opaque;
+        }
+        else if (packet->dts != AV_NOPTS_VALUE)
+        {
+            video_pts = packet->dts;
+        }
+        else
+        {
+            video_pts = 0;
+        }
+
+        video_pts *= av_q2d(is->video_st->time_base);
+        video_pts = synchronize_video(is, pFrame, video_pts);
+
+        if (is->seek_flag_video)
+        {
+            //发生了跳转 则跳过关键帧到目的时间的这几帧
+           if (video_pts < is->seek_time)
+           {
+               av_free_packet(packet);
+               continue;
+           }
+           else
+           {
+               is->seek_flag_video = 0;
+           }
+        }
+
+        while(1)
+        {
+            if (is->quit)
+            {
+                break;
+            }
+
+            audio_pts = is->audio_clock;
+
+            //主要是 跳转的时候 我们把video_clock设置成0了
+            //因此这里需要更新video_pts
+            //否则当从后面跳转到前面的时候 会卡在这里
+            video_pts = is->video_clock;
+
+
+            if (video_pts <= audio_pts) break;
+
+            int delayTime = (video_pts - audio_pts) * 1000;
+
+            delayTime = delayTime > 5 ? 5:delayTime;
+
+            SDL_Delay(delayTime);
+        }
+
+        if (got_picture) {
+            sws_scale(img_convert_ctx,
+                    (uint8_t const * const *) pFrame->data,
+                    pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,
+                    pFrameRGB->linesize);
+
+            //把这个RGB数据 用QImage加载
+            QImage tmpImg((uchar *)out_buffer_rgb,pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB32);
+            QImage image = tmpImg.copy(); //把图像复制一份 传递给界面显示
+            is->player->disPlayVideo(image); //调用激发信号的函数
+        }
+
+        av_free_packet(packet);
+
+    }
+
+    av_free(pFrame);
+    av_free(pFrameRGB);
+    av_free(out_buffer_rgb);
+
+    if (!is->quit)
+    {
+        is->quit = true;
+    }
+
+    is->videoThreadFinished = true;
+
+    return 0;
+}
+
+
+VideoPlayer_Thread::VideoPlayer_Thread()
+{
+
+    mVideoWidget = new VideoPlayer_ShowVideoWidget;
+    connect(this,SIGNAL(sig_GetOneFrame(QImage)),mVideoWidget,SLOT(slotGetOneFrame(QImage)));
+
+    mPlayerState = Stop;
+}
+
+VideoPlayer_Thread::~VideoPlayer_Thread()
+{
+
+}
+
+bool VideoPlayer_Thread::setFileName(QString path)
+{
+    if (mPlayerState != Stop)
+    {
+        return false;
+    }
+
+    mFileName = path;
+
+    mPlayerState = Playing;
+    emit sig_StateChanged(Playing);
+
+    this->start(); //启动线程
+
+    return true;
+
+}
+
+bool VideoPlayer_Thread::play()
+{
+    mVideoState.isPause = false;
+
+    if (mPlayerState != Pause)
+    {
+        return false;
+    }
+
+    mPlayerState = Playing;
+    emit sig_StateChanged(Playing);
+
+    return true;
+}
+
+bool VideoPlayer_Thread::pause()
+{
+    mVideoState.isPause = true;
+
+    if (mPlayerState != Playing)
+    {
+        return false;
+    }
+
+    mPlayerState = Pause;
+
+    emit sig_StateChanged(Pause);
+
+    return true;
+}
+
+bool VideoPlayer_Thread::stop(bool isWait)
+{
+    if (mPlayerState == Stop)
+    {
+        return false;
+    }
+
+    mVideoState.quit = 1;
+
+    mPlayerState = Stop;
+    emit sig_StateChanged(Stop);
+
+    if (isWait)
+    {
+        while(!mVideoState.readThreadFinished || !mVideoState.videoThreadFinished)
+        {
+            SDL_Delay(10);
+        }
+    }
+
+    ///关闭SDL音频播放设备
+    if (mVideoState.audioID != 0)
+    {
+        SDL_LockAudio();
+        SDL_PauseAudioDevice(mVideoState.audioID,1);
+        SDL_UnlockAudio();
+
+        mVideoState.audioID = 0;
+    }
+
+
+    return true;
+}
+
+void VideoPlayer_Thread::seek(int64_t pos)
+{
+    if(!mVideoState.seek_req)
+    {
+        mVideoState.seek_pos = pos;
+        mVideoState.seek_req = 1;
+    }
+}
+
+double VideoPlayer_Thread::getCurrentTime()
+{
+    return mVideoState.audio_clock;
+}
+
+int64_t VideoPlayer_Thread::getTotalTime()
+{
+    return mVideoState.ic->duration;
+}
+
+void VideoPlayer_Thread::disPlayVideo(QImage img)
+{
+    emit sig_GetOneFrame(img);  //发送信号
+}
+
+void VideoPlayer_Thread::run()
+{
+    char file_path[1280] = {0};;
+
+    strcpy(file_path,mFileName.toUtf8().data());
+
+    memset(&mVideoState,0,sizeof(VideoState)); //为了安全起见  先将结构体的数据初始化成0了
+
+    VideoState *is = &mVideoState;
+
+    AVFormatContext *pFormatCtx;
+    AVCodecContext *pCodecCtx;
+    AVCodec *pCodec;
+
+    AVCodecContext *aCodecCtx;
+    AVCodec *aCodec;
+
+    int audioStream ,videoStream, i;
+
+
+    //Allocate an AVFormatContext.
+    pFormatCtx = avformat_alloc_context();
+
+    if (avformat_open_input(&pFormatCtx, file_path, NULL, NULL) != 0) {
+        printf("can't open the file. \n");
+        return;
+    }
+
+    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
+        printf("Could't find stream infomation.\n");
+        return;
+    }
+
+    videoStream = -1;
+    audioStream = -1;
+
+    ///循环查找视频中包含的流信息,
+    for (i = 0; i < pFormatCtx->nb_streams; i++) {
+        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+        {
+            videoStream = i;
+        }
+        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO  && audioStream < 0)
+        {
+            audioStream = i;
+        }
+    }
+
+    ///如果videoStream为-1 说明没有找到视频流
+    if (videoStream == -1) {
+        printf("Didn't find a video stream.\n");
+        return;
+    }
+
+    if (audioStream == -1) {
+        printf("Didn't find a audio stream.\n");
+        return;
+    }
+
+    is->ic = pFormatCtx;
+    is->videoStream = videoStream;
+    is->audioStream = audioStream;
+
+    emit sig_TotalTimeChanged(getTotalTime());
+
+    if (audioStream >= 0) {
+        /* 所有设置SDL音频流信息的步骤都在这个函数里完成 */
+        audio_stream_component_open(&mVideoState, audioStream);
+    }
+
+    ///查找音频解码器
+    aCodecCtx = pFormatCtx->streams[audioStream]->codec;
+    aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
+
+    if (aCodec == NULL) {
+        printf("ACodec not found.\n");
+        return;
+    }
+
+    ///打开音频解码器
+    if (avcodec_open2(aCodecCtx, aCodec, NULL) < 0) {
+        printf("Could not open audio codec.\n");
+        return;
+    }
+
+    is->audio_st = pFormatCtx->streams[audioStream];
+
+    ///查找视频解码器
+    pCodecCtx = pFormatCtx->streams[videoStream]->codec;
+    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
+
+    if (pCodec == NULL) {
+        printf("PCodec not found.\n");
+        return;
+    }
+
+    ///打开视频解码器
+    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
+        printf("Could not open video codec.\n");
+        return;
+    }
+
+    is->video_st = pFormatCtx->streams[videoStream];
+    packet_queue_init(&is->videoq);
+
+    ///创建一个线程专门用来解码视频
+    is->video_tid = SDL_CreateThread(video_thread, "video_thread", &mVideoState);
+
+
+    is->player = this;
+
+//    int y_size = pCodecCtx->width * pCodecCtx->height;
+
+    AVPacket *packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packet 用来存放读取的视频
+//    av_new_packet(packet, y_size); //av_read_frame 会给它分配空间 因此这里不需要了
+
+    av_dump_format(pFormatCtx, 0, file_path, 0); //输出视频信息
+
+    while (1)
+    {
+        if (is->quit)
+        {
+            //停止播放了
+            break;
+        }
+
+        if (is->seek_req)
+        {
+            int stream_index = -1;
+            int64_t seek_target = is->seek_pos;
+
+            if (is->videoStream >= 0)
+                stream_index = is->videoStream;
+            else if (is->audioStream >= 0)
+                stream_index = is->audioStream;
+
+            AVRational aVRational = {1, AV_TIME_BASE};
+            if (stream_index >= 0) {
+                seek_target = av_rescale_q(seek_target, aVRational,
+                        pFormatCtx->streams[stream_index]->time_base);
+            }
+
+            if (av_seek_frame(is->ic, stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) {
+                fprintf(stderr, "%s: error while seeking\n",is->ic->filename);
+            } else {
+                if (is->audioStream >= 0) {
+                    AVPacket *packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packet
+                    av_new_packet(packet, 10);
+                    strcpy((char*)packet->data,FLUSH_DATA);
+                    packet_queue_flush(&is->audioq); //清除队列
+                    packet_queue_put(&is->audioq, packet); //往队列中存入用来清除的包
+                }
+                if (is->videoStream >= 0) {
+                    AVPacket *packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packet
+                    av_new_packet(packet, 10);
+                    strcpy((char*)packet->data,FLUSH_DATA);
+                    packet_queue_flush(&is->videoq); //清除队列
+                    packet_queue_put(&is->videoq, packet); //往队列中存入用来清除的包
+                    is->video_clock = 0;
+                }
+            }
+            is->seek_req = 0;
+            is->seek_time = is->seek_pos / 1000000.0;
+            is->seek_flag_audio = 1;
+            is->seek_flag_video = 1;
+        }
+
+        //这里做了个限制  当队列里面的数据超过某个大小的时候 就暂停读取  防止一下子就把视频读完了,导致的空间分配不足
+        /* 这里audioq.size是指队列中的所有数据包带的音频数据的总量或者视频数据总量,并不是包的数量 */
+        //这个值可以稍微写大一些
+        if (is->audioq.size > MAX_AUDIO_SIZE || is->videoq.size > MAX_VIDEO_SIZE) {
+            SDL_Delay(10);
+            continue;
+        }
+
+        if (is->isPause == true)
+        {
+            SDL_Delay(10);
+            continue;
+        }
+
+        if (av_read_frame(pFormatCtx, packet) < 0)
+        {
+            is->readFinished = true;
+
+            if (is->quit)
+            {
+                break; //解码线程也执行完了 可以退出了
+            }
+
+            SDL_Delay(10);
+            continue;
+        }
+
+        if (packet->stream_index == videoStream)
+        {
+            packet_queue_put(&is->videoq, packet);
+            //这里我们将数据存入队列 因此不调用 av_free_packet 释放
+        }
+        else if( packet->stream_index == audioStream )
+        {
+            packet_queue_put(&is->audioq, packet);
+            //这里我们将数据存入队列 因此不调用 av_free_packet 释放
+        }
+        else
+        {
+            // Free the packet that was allocated by av_read_frame
+            av_free_packet(packet);
+        }
+    }
+
+    ///文件读取结束 跳出循环的情况
+    ///等待播放完毕
+    while (!is->quit) {
+        SDL_Delay(100);
+    }
+
+    stop();
+
+    avcodec_close(pCodecCtx);
+    avformat_close_input(&pFormatCtx);
+
+    is->readThreadFinished = true;
+
+}

+ 151 - 0
src/videoplayer/videoplayer_thread.h

@@ -0,0 +1,151 @@
+/**
+ * 叶海辉
+ * QQ群121376426
+ * http://blog.yundiantech.com/
+ */
+
+#ifndef VIDEOPLAYER_THREAD_H
+#define VIDEOPLAYER_THREAD_H
+
+#include <QThread>
+#include <QImage>
+
+extern "C"
+{
+    #include "libavcodec/avcodec.h"
+    #include "libavformat/avformat.h"
+    #include <libavutil/time.h>
+    #include "libavutil/pixfmt.h"
+    #include "libswscale/swscale.h"
+    #include "libswresample/swresample.h"
+
+    #include <SDL.h>
+    #include <SDL_audio.h>
+    #include <SDL_types.h>
+    #include <SDL_name.h>
+    #include <SDL_main.h>
+    #include <SDL_config.h>
+}
+
+#include "videoplayer/videoplayer_showvideowidget.h"
+
+typedef struct PacketQueue {
+    AVPacketList *first_pkt, *last_pkt;
+    int nb_packets;
+    int size;
+    SDL_mutex *mutex;
+    SDL_cond *cond;
+} PacketQueue;
+
+#define VIDEO_PICTURE_QUEUE_SIZE 1
+#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
+
+#define MAX_AUDIO_SIZE (25 * 16 * 1024)
+#define MAX_VIDEO_SIZE (25 * 256 * 1024)
+
+class VideoPlayer_Thread; //前置声明
+
+typedef struct VideoState {
+    AVFormatContext *ic;
+    int videoStream, audioStream;
+    AVFrame *audio_frame;// 解码音频过程中的使用缓存
+    PacketQueue audioq;
+    AVStream *audio_st; //音频流
+    unsigned int audio_buf_size;
+    unsigned int audio_buf_index;
+    AVPacket audio_pkt;
+    uint8_t *audio_pkt_data;
+    int audio_pkt_size;
+    uint8_t *audio_buf;
+    DECLARE_ALIGNED(16,uint8_t,audio_buf2) [AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
+    enum AVSampleFormat audio_src_fmt;
+    enum AVSampleFormat audio_tgt_fmt;
+    int audio_src_channels;
+    int audio_tgt_channels;
+    int64_t audio_src_channel_layout;
+    int64_t audio_tgt_channel_layout;
+    int audio_src_freq;
+    int audio_tgt_freq;
+    struct SwrContext *swr_ctx; //用于解码后的音频格式转换
+    int audio_hw_buf_size;
+
+    double audio_clock; ///音频时钟
+    double video_clock; ///<pts of last decoded frame / predicted pts of next decoded frame
+
+    AVStream *video_st;
+    PacketQueue videoq;
+
+    /// 跳转相关的变量
+    int             seek_req; //跳转标志
+    int64_t         seek_pos; //跳转的位置 -- 微秒
+    int             seek_flag_audio;//跳转标志 -- 用于音频线程中
+    int             seek_flag_video;//跳转标志 -- 用于视频线程中
+    double          seek_time; //跳转的时间(秒)  值和seek_pos是一样的
+
+    ///播放控制相关
+    bool isPause;  //暂停标志
+    bool quit;  //停止
+    bool readFinished; //文件读取完毕
+    bool readThreadFinished;
+    bool videoThreadFinished;
+
+    SDL_Thread *video_tid;  //视频线程id
+    SDL_AudioDeviceID audioID;
+
+    VideoPlayer_Thread *player; //记录下这个类的指针  主要用于在线程里面调用激发信号的函数
+
+} VideoState;
+
+class VideoPlayer_Thread : public QThread
+{
+    Q_OBJECT
+
+public:
+
+    enum PlayerState
+    {
+        Playing,
+        Pause,
+        Stop
+    };
+
+    explicit VideoPlayer_Thread();
+    ~VideoPlayer_Thread();
+
+    bool setFileName(QString path);
+
+    bool play();
+    bool pause();
+    bool stop(bool isWait = false); //参数表示是否等待所有的线程执行完毕再返回
+
+    void seek(int64_t pos); //单位是微秒
+
+    int64_t getTotalTime(); //单位微秒
+    double getCurrentTime(); //单位秒
+
+    void disPlayVideo(QImage img);
+
+    QWidget *getVideoWidget(){return mVideoWidget;}
+
+signals:
+    void sig_GetOneFrame(QImage); //没获取到一帧图像 就发送此信号
+
+    void sig_StateChanged(VideoPlayer_Thread::PlayerState state);
+    void sig_TotalTimeChanged(qint64 uSec); //获取到视频时长的时候激发此信号
+
+protected:
+    void run();
+
+private:
+    QString mFileName;
+
+    VideoState mVideoState;
+
+    PlayerState mPlayerState; //播放状态
+
+    ///用自己的控件替代SLD 是因为SDL会导致QSS样式失效
+    VideoPlayer_ShowVideoWidget *mVideoWidget; //显示视频用的控件
+
+};
+
+#endif // VIDEOPLAYER_THREAD_H

+ 177 - 0
src/videoplayer/widget/VideoSlider.cpp

@@ -0,0 +1,177 @@
+#include "VideoSlider.h"
+
+#include <QDebug>
+#include <QTimer>
+#include <QResizeEvent>
+#include <QStyle>
+
+VideoSlider::VideoSlider(QWidget *parent) :
+    QSlider(parent)
+{
+    setMouseTracking(true);
+
+    this->setOrientation(Qt::Horizontal);
+
+    isSliderMoving = false;
+
+    m_timer = new QTimer;
+    m_timer->setInterval(100);
+    connect(m_timer,SIGNAL(timeout()),this,SLOT(slotTimerTimeOut()));
+
+    m_timer_mousemove = new QTimer;
+    m_timer_mousemove->setInterval(100);
+    connect(m_timer_mousemove,SIGNAL(timeout()),this,SLOT(slotMousemoveTimerTimeOut()));
+}
+
+VideoSlider::~VideoSlider()
+{
+
+}
+
+void VideoSlider::resizeEvent(QResizeEvent *event)
+{
+//    qDebug()<<"void MySlider::resizeEvent(QResizeEvent *event)";
+}
+
+void VideoSlider::mousePressEvent(QMouseEvent *event)
+{
+//    isSliderMoving = true;
+
+
+    int posX = event->pos().x();
+
+    int w = this->width();
+
+//    qint64 value = posX*1.0/w * this->maximum();
+
+    int value = QStyle::sliderValueFromPosition(minimum(), maximum(), event->pos().x(), width());
+
+    setValue(value);
+
+    qDebug()<<value<<maximum();
+
+    emit sig_valueChanged(value);
+//    emit valueChanged(value);
+//    QSlider::mousePressEvent(event);
+}
+
+void VideoSlider::mouseMoveEvent(QMouseEvent *event)
+{
+//    qDebug()<<"void MySlider::mouseMoveEvent(QMouseEvent *event)"<<event->pos();
+
+//    if (isSliderMoving)
+//    {
+//        m_timer->stop();
+//        videoThread->hideIn();
+//    }
+//    else
+//    {
+//        m_posX = event->pos().x();
+
+//        m_timer_mousemove->stop();
+//        m_timer_mousemove->start();
+//    }
+
+    m_posX = event->pos().x();
+
+    m_timer_mousemove->stop();
+    m_timer_mousemove->start();
+
+    QSlider::mouseMoveEvent(event);
+
+}
+
+void VideoSlider::mouseReleaseEvent(QMouseEvent *event)
+{
+//    emit sig_valueChanged(this->value());
+//    isSliderMoving = false;
+//    QSlider::mouseReleaseEvent(event);
+}
+
+void VideoSlider::enterEvent(QEvent *)
+{
+    m_timer->stop();
+}
+
+void VideoSlider::leaveEvent(QEvent *)
+{
+    m_timer_mousemove->stop();
+    m_timer->start();
+}
+
+bool VideoSlider::seek()
+{
+    return true;
+}
+
+void VideoSlider::setValue(int value)
+{
+    if (!isSliderMoving)
+    QSlider::setValue(value);
+}
+
+//void VideoSlider::setCutMode()
+//{
+//    videoThread->setCutMode();
+//    connect(videoThread,SIGNAL(sig_setStart(qint64)),this,SIGNAL(sig_setStart(qint64)));
+//    connect(videoThread,SIGNAL(sig_setEnd(qint64)),this,SIGNAL(sig_setEnd(qint64)));
+//}
+
+bool VideoSlider::openFile(char*fileName)
+{
+//    videoThread->openFile(fileName);
+
+    return true;
+}
+
+bool VideoSlider::closeFile()
+{
+
+
+    return 0;
+}
+
+//void VideoSliderView::slotTotalTimeChanged(qint64 uSec)
+//{
+//    setRange(0,uSec);
+//}
+
+void VideoSlider::slotTimerTimeOut()
+{
+//    qDebug()<<videoThread->getWidget()->hasFocus();
+//    qDebug()<<videoThread->getWidget()->geometry()<<QCursor::pos()<<videoThread->getWidget()->geometry().contains(QCursor::pos());
+//    if (!videoThread->getWidget()->geometry().contains(QCursor::pos()))
+//    {
+//        m_timer->stop();
+////        videoThread->hideIn();
+//    }
+}
+
+void VideoSlider::slotMousemoveTimerTimeOut()
+{
+
+    m_timer_mousemove->stop();
+
+    int w = this->width();
+
+//    qint64 value = m_posX*1.0/w*videoThread->getTotalTime();
+
+//    this->setValue(value);
+
+    QPoint point = this->mapToGlobal(QPoint(0,0));
+    int width = this->width();
+
+    if (parent() != NULL)
+    {
+        QWidget *widget = (QWidget *)this->parent();
+        point = widget->mapToGlobal(QPoint(0,0));
+
+        width = widget->width();
+    }
+
+//    videoThread->showOut(point,width);
+
+////    qDebug()<<value<<videoThread->getTotalTime();
+
+//    videoThread->seek(value);
+}

+ 53 - 0
src/videoplayer/widget/VideoSlider.h

@@ -0,0 +1,53 @@
+#ifndef VIDEOSLIDER_H
+#define VIDEOSLIDER_H
+
+#include <QWidget>
+#include <QSlider>
+
+namespace Ui {
+class VideoSlider;
+}
+
+class VideoSlider : public QSlider
+{
+    Q_OBJECT
+
+public:
+    explicit VideoSlider(QWidget *parent = 0);
+    ~VideoSlider();
+
+    bool openFile(char*fileName);
+    bool closeFile();
+    void setValue(int value);
+    bool seek();
+
+signals:
+    void sig_clicked(qint64 mSec);
+    void sig_setStart(qint64 mSec);
+    void sig_setEnd(qint64 mSec);
+
+    void sig_valueChanged(int);
+
+protected:
+    void resizeEvent(QResizeEvent *);
+    void mousePressEvent(QMouseEvent *event);
+    void mouseMoveEvent(QMouseEvent *event);
+    void mouseReleaseEvent(QMouseEvent *event);
+    void enterEvent(QEvent *);
+    void leaveEvent(QEvent *);
+
+private:
+    QTimer * m_timer_mousemove;
+    QTimer * m_timer;
+
+    int m_posX;
+
+    bool isSliderMoving;
+
+private slots:
+    void slotTimerTimeOut();
+    void slotMousemoveTimerTimeOut();
+
+};
+
+#endif // VIDEOSLIDERVIEW_H

+ 2 - 2
说明.txt

@@ -1,7 +1,7 @@
 这是Qt的工程,建议使用Qt Creator 打开
 
 
-从零开始学习音视频编程技术(十) FFMPEG Qt视频播放器之播放控制
+从零开始学习音视频编程技术(十一) FFMPEG Qt视频播放器之美化界面
 
 FFMPEG的版本是2.5.2
 SDL的版本是2.04
@@ -10,7 +10,7 @@ SDL
 
 
 关于代码的解释 请参考:
-http://blog.yundiantech.com/?log=blog&id=13
+http://blog.yundiantech.com/?log=blog&id=14
 
 
 Qt开发环境的搭建 请参考: