Qt的核心之一就是信號與槽,信號與槽實現采用了類似觀察者模式。
在面向對象的編程中,都會創建很多實例,而每個實例都是獨立的,要想每個實例能夠協同合作,那么就會需要一種對象間傳遞消息的機制,在很多框架中都采用回調函數來進行對象間信息傳遞。
回調函數就是一個函數指針,如果想要一個處理函數通知一些事件,你需要將這個指針傳遞給處理函數,處理函數在適當時間調用回調函數。MFC就是使用的回調函數,但回調可能是不直觀的,不易于理解的,并且也不能保證是類型安全的。
所謂的對象之間的通信,從程序設計語言語法角度來看就是函數調用的問題,只不過是某個對象的成員函數調用另一個對象的成員函數而已,本文從語法角度講解信號和槽的原理,這樣更容易理解信號和槽的實現原理。
如上圖,假設函數f需要g的處理結果,有以下幾種處理方式:
最簡單的方式就是直接調用函數g,但這種方式有一個明顯的缺點,必須知道函數g的名稱“g”以及函數g的參數類型。但是若f只需要g的處理結果就可以了,而g的處理結果不一定是由函數g來完成,它也可以是x、y或其他函數來完成,那么這種直接調用函數的方式就無法勝任了,因為系統不知道用戶會使用哪個函數來完成這種處理結果,也就是系統不知道調用的函數名究竟是g、x或其他名稱。
另一種方式就是回調函數,即在函數f中使用一個指向函數的指針去調用需要的函數,這樣就可以調用任意名稱的函數(只要函數類型與指針相同即可),此時只要是完成了函數g功能的函數都可以作為函數f的結果被調用,這樣就不會被函數名稱所限制。比如
(2)信號與槽 與 回調函數的區別
回調函數的本質是基于“你想讓別人的代碼執行你的代碼,而別人的代碼你又不能動”這種情況產生的。回調函數是函數指針的一種用法,如果多個類都需要關注某個類的狀態變化,此時需要在被被關注的類中維護一個列表,以存放多個回調函數的地址。對于每一個被關注的類,都需要做類似的工作,因此這種做法不靈活。回調函數的例子:
【領更多QT學習資料,點擊下方鏈接免費領取↓↓,先碼住不迷路~】
點擊→Qt開發(資料筆記文檔+視頻教程+項目實戰)
#include <iostream>
void printWelcome()
{
std::cout << "Welcome!\n";
}
void printBye()
{
std::cout << "Bye!\n";
}
void callback(void(*print)(int))
{
print();
}
void main(void)
{
callback(printWelcome);
callback(printGoodbye);
}
Qt為了消除回調函數等的弊端,從而開發了一種新的消息傳遞機制,即信號和槽。
順帶提一句,Qt提供了一種機制,能夠自動、有效的組織和管理繼承自QObject的Qt對象,這種機制就是對象樹。這種機制在界面變成上是有好處的,能夠幫助程序員緩解內存泄露的問題,比如當應用程序創建了一個具有父窗口部件的對象時,該對象將被加入父窗口部件的孩子列表。當應用程序銷毀父窗口部件時,該父對象的孩子列表中的對象將被一一刪除。這讓我們在編程時,能夠將主要精力放在系統的業務上,提高編程效率,同時也保證了系統的穩健性。所以new了一個父窗口后,只要delete父窗口后,那它的子窗口都會被自動釋放,釋放順序(即析構順序)與這些子對象的構造順序相反。
例如,當我們要求鼠標點擊某個按鈕時,對應的窗口就需要關閉,那么這個按鈕就會發出一個點擊信號,而窗口接收到這個信號后執行關閉窗口。那么,這個信號就是按鈕被點擊,而槽就是窗口執行關閉函數。可以將信號和槽理解成“命令-執行”,即信號就是命令,槽就是執行命令。
(1)信號
當一個對象的內部狀態發生改變時,如果其它對象對它的狀態改變需要作出反應,這時就應該讓這個類發出狀態改變的信號。聲明信號使用signals關鍵字。發送信號使用emit關鍵字。信號的使用需要主要的點:
所有的信號聲明都是公有的,所以Qt規定不能在signals前面加public、private、protected;
所有的信號都沒有返回值,所以返回值都用void;
所有的信號都不需要定義,只需要聲明就可以;
信號所屬的類必須直接或間接繼承自QOBject類,并且開頭包含Q_OBJECT。
在同一個線程中,當一個信號被emit發出時,會立即執行其槽函數,等槽函數執行完畢后,才會執行emit后面的代碼,如果一個信號連接了多個槽,那么會等所有的槽函數執行完畢后才執行后面的代碼,槽函數的執行順序是按照它們連接時的順序執行的。不同線程中(即跨線程時),槽函數的執行順序是隨機的。
信號與槽機制要求信號和槽的參數一致,所謂一致,是參數類型一致。如果不一致,允許的情況是,信號的參數可以比槽函數的參數多,即便如此,槽函數存在的那些參數的順序也必須和信號的前面幾個一致起來。這是因為,可以在槽函數中選擇忽略信號傳來的數據(也就是槽函數的參數比信號的少),但是不允許槽函數的參數比信號的多,因為信號根本沒有這個數據,也就無法在槽函數中使用。
(2)槽
槽其實就是普通的C++函數,它可以是虛函數,static函數,也可以被重載,可以是公有的、保護的、私有的,當然也可以被其他C++成員函數調用,它唯一特點就是能和信號連接。當和它連接的信號被發出時,這個槽就會被調用,而且槽所在的類也需要直接或間接繼承QObject,然后添加Q_OBJECT,槽函數因為是普通的C++函數,所以需要實現。
在qt4中,聲明槽可以使用:public/protected/private slots:
在Qt5中不需要使用這些聲明,每個函數都可以被當作是槽函數,而且還可以使用Lambda表達式來作為槽。不過為了程序的可讀性,還是推薦槽函數要聲明一下。
(3)信號與槽的連接
使用connect函數,有兩個原型。
原型1:
static QMetaObject::Connection connect(
const QObject *sender, //信號發送對象指針
const char *signal, //信號函數字符串,使用SIGNAL()
const QObject *receiver, //槽函數對象指針
const char *member, //槽函數字符串,使用SLOT()
Qt::ConnectionType=Qt::AutoConnection);
如:
connect(pushButton, SIGNAL(clicked()), dialog, SLOT(close()));
Qt4和Qt5都可以使用這種連接方式。
原型2:
static QMetaObject::Connection connect(
const QObject *sender, //信號發送對象指針
const QMetaMethod &signal, //信號函數地址
const QObject *receiver, //槽函數對象指針
const QMetaMethod &method, //槽函數地址
Qt::ConnectionType type=Qt::AutoConnection);
如:
connect(pushButton, &QPushButton::clicked, dialog, &QDialog::close);
這是Qt5新增的連接方式,這使得在編譯期間就可以進行拼寫檢查,參數檢查,類型檢查,并且支持相容參數的兼容性轉換。
(4)信號與槽的多種用法
一個信號可以和多個槽相連
這時槽的執行順序和在不在同一個線程上有關,同一線程,槽的執行順序和聲明順序有關,跨線程時,執行順序是不確定的。
多個信號可以連接到一個槽
只要任意一個信號發出,這個槽就會被調用。
一個信號可以連接到另外的一個信號
當第一個信號發出時,第二個信號被發出。除此之外,這種信號-信號的形式和信號-槽的形式沒有什么區別。
槽可以被取消連接
主動取消連接使用disconnect()函數。
使用Lambda 表達式
能夠支持 Qt 5 的編譯器都是支持 Lambda 表達式。
第5個參數可以取以下的值,分別代表的意義如下:
當多個信號連接一個槽時,有時需要判斷是哪個對象發來的,那么可以調用sender()函數獲取對象指針,返回為QObject指針。
QObject* sender();
現在來看看信號與槽怎么到底怎么實現的? 這里為了說明信號與槽的原理,下面以一個簡單的信號與槽例程來說明。代碼如下:
定義一個類SignalsAndSlots,在類中定義一個信號和槽。
SignalsAndSlots.h文件
#pragma once
#include <QtCore/QObject>
class SignalsAndSlots : public QObject
{
Q_OBJECT
public:
explicit SignalsAndSlots(QObject *parent=0);
signals:
void sigPrint(const QString& text);
public slots:
void onPrint(const QString& text);
};
SignalsAndSlots.cpp 文件
【領更多QT學習資料,點擊下方鏈接免費領取↓↓,先碼住不迷路~】
點擊→Qt開發(資料筆記文檔+視頻教程+項目實戰)
#include <QtCore/QDebug>
#include "SignalsAndSlots.h"
SignalsAndSlots::SignalsAndSlots(QObject *parent) : QObject(parent)
{
connect(this, SIGNAL(sigPrint(QString)), this, SLOT(onPrint(QString)));
emit sigPrint("Hello");
}
void SignalsAndSlots::onPrint(const QString &text)
{
qDebug() << text;
}
main.cpp 文件
#include <QtCore/QCoreApplication>
#include "SignalsAndSlots.h"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
SignalsAndSlots sigSlot;
return app.exec();
}
編譯程序,會出現以下編譯錯誤。
(1)moc預編譯器
moc(Meta-Object Compiler)元對象預編譯器。moc讀取c++頭文件。如果它找到包含Q_OBJECT宏的一個或多個類聲明,它會生成一個包含這些類的元對象代碼的c++源文件,并且以moc_作為前綴。信號和槽機制、運行時類型信息和動態屬性系統需要元對象代碼。由moc生成的c++源文件必須編譯并與類的實現聯系起來。通常,moc不是手工調用的,而是由構建系統自動調用的,因此它不需要程序員額外的工作。
(2)Q_OBJECT 宏
下面看看Q_OBJECT真面目,其宏定義如下:
#define Q_OBJECT \
public: \
Q_OBJECT_CHECK \
QT_WARNING_PUSH \
Q_OBJECT_NO_OVERRIDE_WARNING \
static const QMetaObject staticMetaObject; \
virtual const QMetaObject *metaObject() const; \
virtual void *qt_metacast(const char *); \
virtual int qt_metacall(QMetaObject::Call, int, void **); \
QT_TR_FUNCTIONS \private: \
Q_OBJECT_NO_ATTRIBUTES_WARNING \
Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
QT_WARNING_POP \ struct QPrivateSignal {}; \
QT_ANNOTATE_CLASS(qt_qobject, "")
將其中的宏再次展開,并去掉一下無用的代碼,如下:
public:
static const QMetaObject staticMetaObject;
virtual const QMetaObject *metaObject() const;
virtual void *qt_metacast(const char *);
virtual int qt_metacall(QMetaObject::Call, int, void **);
static inline QString tr(const char *s, const char *c=nullptr, int n=-1)
{ return staticMetaObject.tr(s, c, n); }
QT_DEPRECATED static inline QString trUtf8(const char *s, const char *c=nullptr, int n=-1)
{ return staticMetaObject.tr(s, c, n); }
private:
static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
struct QPrivateSignal {};
你也可以在signalsandslots.h中用上面的代碼替換掉Q_OBJECT ,但你會發現還需要實現Q_OBJECT擴展后所帶來的變量和函數的定義。而這些定義都已經被寫入到了moc_signalsandslots.cpp文件中了,這也就是為什么需要將moc_signalsandslots.cpp一起編譯的原因了。否則,這個類是不完整的。
打開生成的moc_signalsandslots.cpp文件,看看里面代碼。你需要在moc_signalsandslots.cpp文件從下往上看代碼:
/*1.首先初始化靜態變量staticMetaObject,并為QMetaObject中的無名結構體賦值*/
QT_INIT_METAOBJECT const QMetaObject SignalsAndSlots::staticMetaObject={ {
&QObject::staticMetaObject,
qt_meta_stringdata_SignalsAndSlots.data,
qt_meta_data_SignalsAndSlots,
qt_static_metacall,
nullptr,
nullptr
} };
/*2.執行對象所對應的信號或槽,或查找槽索引*/
void SignalsAndSlots::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c==QMetaObject::InvokeMetaMethod) {
auto *_t=static_cast<SignalsAndSlots *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->sigPrint((*reinterpret_cast< const QString(*)>(_a[1]))); break;
case 1: _t->onPrint((*reinterpret_cast< const QString(*)>(_a[1]))); break;
default: ;
}
} else if (_c==QMetaObject::IndexOfMethod) {
int *result=reinterpret_cast<int *>(_a[0]);
{
using _t=void (SignalsAndSlots::*)(const QString & );
if (*reinterpret_cast<_t *>(_a[1])==static_cast<_t>(&SignalsAndSlots::sigPrint)) {
*result=0;
return;
}
}
}
}
/*3.存儲元對象信息,包括信號和槽機制、運行時類型信息和動態屬性系統*/
static const uint qt_meta_data_SignalsAndSlots[]={
// content:
8, // revision
0, // classname
0, 0, // classinfo
2, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
1, // signalCount
// signals: name, argc, parameters, tag, flags
1, 1, 24, 2, 0x06 /* Public */,
// slots: name, argc, parameters, tag, flags
4, 1, 27, 2, 0x0a /* Public */,
// signals: parameters
QMetaType::Void, QMetaType::QString, 3,
// slots: parameters
QMetaType::Void, QMetaType::QString, 3,
0 // eod
};
/*4.初始化qt_meta_stringdata_SignalsAndSlots,并且將所有函數拼接成字符串
【領更多QT學習資料,點擊下方鏈接免費領取↓↓,先碼住不迷路~】
點擊→Qt開發(資料筆記文檔+視頻教程+項目實戰)
static const qt_meta_stringdata_SignalsAndSlots_t qt_meta_stringdata_SignalsAndSlots={
{
QT_MOC_LITERAL(0, 0, 15), // "SignalsAndSlots"
QT_MOC_LITERAL(1, 16, 8), // "sigPrint"
QT_MOC_LITERAL(2, 25, 0), // ""
QT_MOC_LITERAL(3, 26, 4), // "text"
QT_MOC_LITERAL(4, 31, 7) // "onPrint"
},
"SignalsAndSlots\0sigPrint\0\0text\0onPrint"
};
#undef QT_MOC_LITERAL
/*5.切分字符串*/
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_SignalsAndSlots_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
/*6.存儲類中的函數及參數信息*/
struct qt_meta_stringdata_SignalsAndSlots_t {
QByteArrayData data[5];
char stringdata0[39];
};
從上面的代碼中,我們得知Qt的元對象系統:信號槽,屬性系統,運行時類信息都存儲在靜態對象staticMetaObject中。
接下來是對另外三個公有接口的定義,在你的代碼中也可以直接調用下面的函數:
//1、獲取元對象,可以調用
const QMetaObject *SignalsAndSlots::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
獲取類名稱
this->metaObject()->className()
//2、這個函數負責將傳遞來到的類字符串描述,轉化為void*
void *SignalsAndSlots::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_meta_stringdata_SignalsAndSlots.stringdata0))
return static_cast<void*>(this);
return QObject::qt_metacast(_clname);
}
//3、調用方法
int SignalsAndSlots::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id=QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c==QMetaObject::InvokeMetaMethod) {
if (_id < 2)
qt_static_metacall(this, _c, _id, _a);
_id -=2;
} else if (_c==QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 2)
*reinterpret_cast<int*>(_a[0])=-1;
_id -=2;
}
return _id;
}
接下來,我們發現在頭文件中聲明的信號,其真正定義是在這里,這也是為什么signal不需要我們定義的原因。
// SIGNAL 0
void SignalsAndSlots::sigPrint(const QString & _t1)
{
void *_a[]={ nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
運行結果
說是關鍵字,其實不準確,實際是宏。
# define QT_ANNOTATE_ACCESS_SPECIFIER(x)
# define Q_SIGNALS public QT_ANNOTATE_ACCESS_SPECIFIER(qt_signal)
# define signals Q_SIGNALS
如果signals被展開的話就是public,所以所有的信號都是公有的,也不需要像槽一樣加public,protected,private的限定符。
# define QT_ANNOTATE_ACCESS_SPECIFIER(x)
# define Q_SLOTS QT_ANNOTATE_ACCESS_SPECIFIER(qt_slot)
# define slots Q_SLOTS
slots和signals一樣,只是沒有了限定符,所以它是否可以被對象調用,就看需求了。
emit
它的宏定義:
# define emit
emit是個空的宏。當它被替換的時候,相當于沒有任何作用。程序其實就是調用了sigPrint()函數,而不是真正意義上的發送一個信號,有很多初學者都是認為當emit的時候,Qt會發信號,實際就是普通函數調用。
(4)信號與槽的實際流程
通過以上的代碼和一頓操作,我們來總結一下信號與槽的具體流程。
moc編譯器(Qt提供)查找頭文件中的signals,slots,標記出信號和槽。
將信號槽信息存儲到類靜態變量staticMetaObject中,并且按聲明順序進行存放,建立索引。
當發現有connect連接時,將信號槽的索引信息放到一個map中,彼此配對。
當調用emit時,調用信號函數,并且傳遞發送信號的對象指針,元對象指針,信號索引,參數列表到active函數
通過active函數找到在map中找到所有與信號對應的槽索引
根據槽索引找到槽函數,執行槽函數。
以上,便是信號槽的整個流程,總的來說就是一個“注冊-索引”機制,并不存在發送系統信號之類的事情。
(5)信號與槽的注意點
1、槽的屬性
public slots:在這個區內聲明的槽意味著所有對象都可將信號和之相連接。這對于組件編程非常有用,你能創建彼此互不了解的對象,將他們的信號和槽進行連接以便信息能夠正確的傳遞。
protected slots:在這個區內聲明的槽意味著當前類及其子類能將信號和之相連接。這適用于那些槽,他們是類實現的一部分,不過其界面接口卻面向外部。
private slots:在這個區內聲明的槽意味著只有類自己能將信號和之相連接。這適用于聯系非常緊密的類。
2、如果發射者和接收者屬于同一個對象的話,那么在connect調用中接收者參數能省略。
3、有三種情況可使用disconnect()函數:
(1)斷開和某個對象相關聯的所有對象。事實上,當我們在某個對象中定義了一個或多個信號,這些信號和另外若干個對象中的槽相關聯,如果我們要切斷這些關聯的話,就能利用這個方法,非常之簡潔。
disconnect( myObject, 0, 0, 0 ) 或 myObject->disconnect()
(2)斷開和某個特定信號的所有關聯。
disconnect( myObject, SIGNAL(mySignal()), 0, 0 ) 或 myObject->disconnect( SIGNAL(mySignal()) )
(3)斷開兩個對象之間的關聯。
disconnect( myObject, 0, myReceiver, 0 ) 或 myObject->disconnect( myReceiver )
在disconnect函數中0能用作一個通配符,分別表示所有信號、所有接收對象、接收對象中的所有槽函數。不過發射者sender不能為0,其他三個參數的值能等于0。
4、定義不能用在signal和slot的參數中。
因為moc工具不擴展#define,所以在signals和slots中攜帶參數的宏就不能正確地工作。
#define SIGNEDNESS(a) unsigned a
signals:
void someSignal( SIGNEDNESS(a) );
5、構造函數不能用在signals或slots聲明區域內。
6、函數指針不能直接作為信號或槽的參數,是不合法的,可以取巧,用typedef,如下:
typedef void (*ApplyFunctionType)(QList*, void*);
public slots:
void apply( ApplyFunctionType, char *);
7、信號和槽不能有缺省參數:因為signal與slot綁定是發生在運行時。
8、信號和槽也不能攜帶模板類參數
如果將信號、槽聲明為模板類參數的話,即使moc工具不報告錯誤,也不可能得到預期的結果,也可以取巧,用typedef
typedef pair IntPair;
public slots:
void setLocation (IntPair location);
9、嵌套的類不能位于信號或槽區域內,也不能有信號或槽。即類b嵌套在類a內,想在類b中聲明信號與槽是不行的。
10、友元聲明不能位于信號或槽聲明區內。相反,他們應該在普通C++的private、protected或public區內進行聲明
(6)槽的執行時間大于信號發送間隔怎么辦?
有兩種情況:
1、如果需要對每個發來的信號都做出處理,那么有兩種方式來解決,即在信號與槽的connect函數中明確第五個參數,將其設置成DirectConnection方式阻塞時編程,或者設置成BlockingQueuedConnection阻塞的方式都可以很好的解決;
2、如果只需要對最新的信號做處理,那么這里也給出兩種方案來處理:
a、槽所在線程設置bool狀態,信號所在線程通過判定這個bool的狀態來確定是否發送信號;
b、槽執行完畢,則向信號所在線程發送返回值,信號所在線程通過判定發來的這個返回值來判定是否繼續對槽所在線程發送新的信號。
之前我們對飛利浦241P8QPJEB這款23.6英寸的專業級商務顯示器進行了深度體驗,而飛利浦這次推出的專業商務顯示器新品系列中還有一款27英寸的272B7QPJEB,它基本上可以看作是241P8QPJEB的2K大屏版,在專業商務應用方面的表現也非常搶眼,特別適合有大屏需求的白領精英人士。那么,本期我們就來針對272B7QPJEB進行深度體驗。
規格參數
可視尺寸:27英寸
寬高比:16比9
面板類型:AH-IPS
最佳分辨率:2560×1440@60Hz
對比度(典型值):1000比1
亮度:350cd/m2
響應時間:5ms
視頻接口:DP+HDMI+VGA
擴展接口:音頻接口(輸入/輸出)
USB 3.0 HUB(1上行4下行)
內置音箱:2W×2
可持續發展性
環境和能源:PowerSensor、能源之星7.0、EPEAT金牌、TCP edge、RoHS
可回收包裝材料:100%
消費后可回收塑料:85%
具體物質:不含聚氯乙烯和溴化 阻燃劑的外殼、無汞、無鉛
合規性和標準
法律許可范圍:CE 標志、FCC B 級、SEMKO、cETLus、CU-EAC、TCO edge、TUV Ergo、TUV/GS、 EPA、WEEE、ICE – 003、UKRAINIAN、CCC認證
參考價格:2099元
長按識別二維碼立刻搶購
家族式白領精英風格外觀
商務風格外觀盡顯白領精英氣質
從外觀來看,272B7QPJEB確實和之前的241P8QPJEB是同樣的白領精英商務風格,時尚、高效的感覺撲面而來,而它家族式的超窄邊框設計和SmartErgoBase人體工學支架尤其搶眼。超窄邊框設計讓272B7QPJEB更適合多屏拼接,而多屏模式對于多任務應用或是查看超高分辨率商業圖片以及超大表格來講都很實用。
可調范圍極大的人體工學支架方便多角度觀看
SmartErgoBase人體工學支架確實是飛利浦這一系列專業商務顯示器的重要賣點之一,通過這項設計,272B7QPJEB可以實現自由度非常高的視角調節,不但方便實現各種多屏拼接模式和超長網頁、圖片瀏覽模式,還能做到最舒適的觀看角度,對長期坐在顯示器前的商務用戶的健康也起到了保護的作用。此外,SmartErgoBase人體工學支架上還特別設計了線纜管理夾,用戶能方便地整理各種電源線和數據線,讓辦公桌變得更整潔,打造更舒適高效的工作環境。
接口豐富,辦公更有效率
多種視頻接口保證了優秀的設備兼容性
272B7QPJEB的接口配置和241P8QPJEB相當,也配備了DisplayPort、HDMI和VGA接口,對于新老電腦的適應性都很好,方便企業批量升級而不用擔心老電腦沒有接口支持。此外,272B7QPJEB也提供了4個USB 3.0接口,其中兩個還支持快充,這對于商務用戶來說也是很方便的功能,平時上班就順便給手機充電,不用低頭去電腦上插拔USB線。
272B7QPJEB和241P8QPJEB一樣,都內置了雙2W立體聲音箱,商務用戶不用再額外購買音箱或耳機就可以直接與同事、客戶分享音視頻內容了。而且,顯示器上還提供了3.5mm音頻輸入/輸出接口,如果用戶要外接音箱或耳機也是可以的。
以人為本,健康節能少不了
品牌LOGO下方內置PowerSensor傳感器,可實現智能節電
272B7QPJEB配備了多項技術來提供節能功能和保護用戶視力。例如在顯示器OSD的SmartImage菜單中選擇省電模式就能讓顯示器進入節能狀態,選擇LowBlue模式則可以進入濾藍光模式,濾除對人眼有害的藍光,保護使用者的眼睛。此外,272B7QPJEB也采用了不閃屏技術,避免了屏幕背光閃爍造成眼睛疲勞的問題,這對于長期使用電腦的商務用戶來說是很有必要的功能。
272B7QPJEB通過了各種嚴格的安規認證,企業可以放心采購
特別值得一提的是,272B7QPJEB和241P8QPJEB一樣支持PowerSensor技術,可以自動偵測使用者是否在顯示器面前,如果使用者離開則會進入節能模式,根據統計數據顯示,PowerSensor技術可以節約80%的顯示器耗電量,這部分電費對于有很多辦公電腦的企業來說可不是一筆小開支。此外,272B7QPJEB還通過了各種嚴格的安規與環保認證,對于正規企業來講,可以放心大量采購。
專業級色彩表現,作圖看圖利器
測試平臺
處理器:Core i7 8700K
內存:芝奇DDR4 3200 8GB×4
主板:華碩ROG STRIX Z370-E GAMING
顯卡:七彩虹iGameGTX1080Ti Vulcan AD
硬盤:三星850Pro 256GB
電源:航嘉MVP P850
操作系統:Windows 10 64bit專業版
校色儀:Spyder4Elite
對于專業商務顯示器來講,色彩表現能力和還原能力也是非常重要的,因為專業商務應用中包括了處理和瀏覽商業美圖和海報,如果顯示器色彩還原有偏差,那就會導致多次返工,不但浪費人力物力成本,也浪費了時間。272B7QPJEB雖然并沒有標稱自己支持廣色域,但241P8QPJEB在色彩方面的出色表現讓我們對272B7QPJEB也很有信心,當然,我們本次測試也采用了Spyder4Elite來校色和檢測。此外,在測試之前,我們先按照Spyder4Elite的提示進行設置和調節,保證顯示器處于標準的測試狀態。
272B7QPJEB的色域表現相當不錯,做到了實測100% sRGB和86% NTSC,這個表現甚至還小小超過了241P8QPJEB
在色彩精準度方面,272B7QPJEB的表現也令人滿意,平均Delta E做到了小于1
272B7QPJEB的色彩測試讓我們眼前一亮,雖然并沒有標稱支持廣色域,但它實測100% sRGB、86% NTSC色域的成績確確實實達到了專業級商務顯示器的水平。而在48色的色彩精準度測試中,272B7QPJEB的平均Delta E值也做到了小于1,綜合色彩還原能力在同價位商務顯示器中算是相當不錯了。
接下來我們使用272B7QPJEB進行了實際應用體驗。由于支持2560×1440高分辨率,272B7QPJEB的畫面顯示十分精細,在正常觀看距離下字體細膩程度也明顯超越1080P顯示器,瀏覽表格時也能顯示更多的內容,辦公效率得到有效提升。
此外,在SmartImage技術支持下,針對不同場景選擇合適的顯示模式能夠獲得更佳的觀感,例如在觀看圖片的時候,就能獲得更艷麗的色彩,而在LowBlue模式下,畫面變得更加柔和溫暖,看起來更加舒服。總的來說,272B7QPJEB的畫面效果是相當不錯的,優秀的面板+飛利浦專業的調校,獲得了相當出色的觀感。
總結:大屏辦公,飛利浦272B7QPJEB堪稱專業之選
飛利浦272B7QPJEB這款大屏幕專業商務顯示器給我們留下深刻印象。在顯示效果方面,它的色彩表現力和色彩還原能力都相當出色,達到了專業商務顯示器應有的水平,即便是用來處理商業圖片和海報也是游刃有余。
在易用性方面,它配備的SmartErgoBase人體工學支架具備超高自由度的調節范圍,配合超窄邊框可以輕松實現各種多屏拼接模式,也非常適合用來展示豎向超長文檔、網頁、海報和表格,提升工作效率。
在接口方面,DP+HDMI+VGA可以適應新老電腦升級,節約企業升級成本,4個USB 3.0接口+3.5mm音頻輸入/輸出接口也提供了便利的功能,而內置音箱更是省去了獨立購買音頻設備的麻煩;在保護使用者用眼健康方面,它提供的LowBlue濾藍光功能和不閃屏功能也是效果顯著。
此外,272B7QPJEB的PowerSensor智能節能功能可節約80%的顯示器耗電量,實實在在為企業節約了運營成本,而且它還通過了各種嚴格的安規與環保認證,更適合正規企業采購。總的來說,272B7QPJEB算得上是一款全能型的大屏幕專業商務顯示器,值得企業用戶優先選擇。
小獅子最喜歡的雞腿 分割線