我正在尝试使用一个与Qt中的Android Switches等效的元素。我在QML中找到了一个ToggleSwitch,但在实际的CQt库中一无所获。我只是错过了什么,还是我必须自己重新实现这个小部件?
这里是@IMAN4K答案的Python 3/PyQt5实现。
对原始实施的改进:
from PyQt5.QtCore import QPropertyAnimation, QRectF, QSize, Qt, pyqtProperty
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import (
QAbstractButton,
QApplication,
QHBoxLayout,
QSizePolicy,
QWidget,
)
class Switch(QAbstractButton):
def __init__(self, parent=None, track_radius=10, thumb_radius=8):
super().__init__(parent=parent)
self.setCheckable(True)
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self._track_radius = track_radius
self._thumb_radius = thumb_radius
self._margin = max(0, self._thumb_radius - self._track_radius)
self._base_offset = max(self._thumb_radius, self._track_radius)
self._end_offset = {
True: lambda: self.width() - self._base_offset,
False: lambda: self._base_offset,
}
self._offset = self._base_offset
palette = self.palette()
if self._thumb_radius > self._track_radius:
self._track_color = {
True: palette.highlight(),
False: palette.dark(),
}
self._thumb_color = {
True: palette.highlight(),
False: palette.light(),
}
self._text_color = {
True: palette.highlightedText().color(),
False: palette.dark().color(),
}
self._thumb_text = {
True: '',
False: '',
}
self._track_opacity = 0.5
else:
self._thumb_color = {
True: palette.highlightedText(),
False: palette.light(),
}
self._track_color = {
True: palette.highlight(),
False: palette.dark(),
}
self._text_color = {
True: palette.highlight().color(),
False: palette.dark().color(),
}
self._thumb_text = {
True: '✔',
False: '✕',
}
self._track_opacity = 1
@pyqtProperty(int)
def offset(self):
return self._offset
@offset.setter
def offset(self, value):
self._offset = value
self.update()
def sizeHint(self): # pylint: disable=invalid-name
return QSize(
4 * self._track_radius + 2 * self._margin,
2 * self._track_radius + 2 * self._margin,
)
def setChecked(self, checked):
super().setChecked(checked)
self.offset = self._end_offset[checked]()
def resizeEvent(self, event):
super().resizeEvent(event)
self.offset = self._end_offset[self.isChecked()]()
def paintEvent(self, event): # pylint: disable=invalid-name, unused-argument
p = QPainter(self)
p.setRenderHint(QPainter.Antialiasing, True)
p.setPen(Qt.NoPen)
track_opacity = self._track_opacity
thumb_opacity = 1.0
text_opacity = 1.0
if self.isEnabled():
track_brush = self._track_color[self.isChecked()]
thumb_brush = self._thumb_color[self.isChecked()]
text_color = self._text_color[self.isChecked()]
else:
track_opacity *= 0.8
track_brush = self.palette().shadow()
thumb_brush = self.palette().mid()
text_color = self.palette().shadow().color()
p.setBrush(track_brush)
p.setOpacity(track_opacity)
p.drawRoundedRect(
self._margin,
self._margin,
self.width() - 2 * self._margin,
self.height() - 2 * self._margin,
self._track_radius,
self._track_radius,
)
p.setBrush(thumb_brush)
p.setOpacity(thumb_opacity)
p.drawEllipse(
self.offset - self._thumb_radius,
self._base_offset - self._thumb_radius,
2 * self._thumb_radius,
2 * self._thumb_radius,
)
p.setPen(text_color)
p.setOpacity(text_opacity)
font = p.font()
font.setPixelSize(1.5 * self._thumb_radius)
p.setFont(font)
p.drawText(
QRectF(
self.offset - self._thumb_radius,
self._base_offset - self._thumb_radius,
2 * self._thumb_radius,
2 * self._thumb_radius,
),
Qt.AlignCenter,
self._thumb_text[self.isChecked()],
)
def mouseReleaseEvent(self, event): # pylint: disable=invalid-name
super().mouseReleaseEvent(event)
if event.button() == Qt.LeftButton:
anim = QPropertyAnimation(self, b'offset', self)
anim.setDuration(120)
anim.setStartValue(self.offset)
anim.setEndValue(self._end_offset[self.isChecked()]())
anim.start()
def enterEvent(self, event): # pylint: disable=invalid-name
self.setCursor(Qt.PointingHandCursor)
super().enterEvent(event)
def main():
app = QApplication([])
# Thumb size < track size (Gitlab style)
s1 = Switch()
s1.toggled.connect(lambda c: print('toggled', c))
s1.clicked.connect(lambda c: print('clicked', c))
s1.pressed.connect(lambda: print('pressed'))
s1.released.connect(lambda: print('released'))
s2 = Switch()
s2.setEnabled(False)
# Thumb size > track size (Android style)
s3 = Switch(thumb_radius=11, track_radius=8)
s4 = Switch(thumb_radius=11, track_radius=8)
s4.setEnabled(False)
l = QHBoxLayout()
l.addWidget(s1)
l.addWidget(s2)
l.addWidget(s3)
l.addWidget(s4)
w = QWidget()
w.setLayout(l)
w.show()
app.exec()
if __name__ == '__main__':
main()
几个月前,我做了一个实现,其视觉效果需要与常见的桌面风格更加一致(C和Python版本可用;Python版本是原型,即它们的工作方式可能不同)。请注意,美学是使用 paintEvent
完全自定义的。不要期望根据系统的不同而产生不同的视觉效果。
C实现
注意:不要忘记includes(在我的示例中没有)。
用法:
SwitchButton* sbtn = new SwitchButton(this); // Default style is Style::ONOFF
bool current = sbtn->value();
sbtn->setValue(!current);
(...).马力士
class SwitchButton : public QWidget
{
Q_OBJECT
Q_DISABLE_COPY(SwitchButton)
public:
enum Style
{
YESNO,
ONOFF,
BOOL,
EMPTY
};
public:
explicit SwitchButton(QWidget* parent = nullptr, Style style = Style::ONOFF);
~SwitchButton() override;
//-- QWidget methods
void mousePressEvent(QMouseEvent *) override;
void paintEvent(QPaintEvent* event) override;
void setEnabled(bool);
//-- Setters
void setDuration(int);
void setValue(bool);
//-- Getters
bool value() const;
signals:
void valueChanged(bool newvalue);
private:
class SwitchCircle;
class SwitchBackground;
void _update();
private:
bool _value;
int _duration;
QLinearGradient _lg;
QLinearGradient _lg2;
QLinearGradient _lg_disabled;
QColor _pencolor;
QColor _offcolor;
QColor _oncolor;
int _tol;
int _borderradius;
// This order for definition is important (these widgets overlap)
QLabel* _labeloff;
SwitchBackground* _background;
QLabel* _labelon;
SwitchCircle* _circle;
bool _enabled;
QPropertyAnimation* __btn_move;
QPropertyAnimation* __back_move;
};
class SwitchButton::SwitchBackground : public QWidget
{
Q_OBJECT
Q_DISABLE_COPY(SwitchBackground)
public:
explicit SwitchBackground(QWidget* parent = nullptr, QColor color = QColor(154, 205, 50), bool rect = false);
~SwitchBackground() override;
//-- QWidget methods
void paintEvent(QPaintEvent* event) override;
void setEnabled(bool);
private:
bool _rect;
int _borderradius;
QColor _color;
QColor _pencolor;
QLinearGradient _lg;
QLinearGradient _lg_disabled;
bool _enabled;
};
class SwitchButton::SwitchCircle : public QWidget
{
Q_OBJECT
Q_DISABLE_COPY(SwitchCircle)
public:
explicit SwitchCircle(QWidget* parent = nullptr, QColor color = QColor(255, 255, 255), bool rect = false);
~SwitchCircle() override;
//-- QWidget methods
void paintEvent(QPaintEvent* event) override;
void setEnabled(bool);
private:
bool _rect;
int _borderradius;
QColor _color;
QColor _pencolor;
QRadialGradient _rg;
QLinearGradient _lg;
QLinearGradient _lg_disabled;
bool _enabled;
};
(...)..cpp
SwitchButton::SwitchButton(QWidget* parent, Style style)
: QWidget(parent)
, _value(false)
, _duration(100)
, _enabled(true)
{
_pencolor = QColor(120, 120, 120);
_lg = QLinearGradient(35, 30, 35, 0);
_lg.setColorAt(0, QColor(210, 210, 210));
_lg.setColorAt(0.25, QColor(255, 255, 255));
_lg.setColorAt(0.82, QColor(255, 255, 255));
_lg.setColorAt(1, QColor(210, 210, 210));
_lg2 = QLinearGradient(50, 30, 35, 0);
_lg2.setColorAt(0, QColor(230, 230, 230));
_lg2.setColorAt(0.25, QColor(255, 255, 255));
_lg2.setColorAt(0.82, QColor(255, 255, 255));
_lg2.setColorAt(1, QColor(230, 230, 230));
_lg_disabled = QLinearGradient(50, 30, 35, 0);
_lg_disabled.setColorAt(0, QColor(200, 200, 200));
_lg_disabled.setColorAt(0.25, QColor(230, 230, 230));
_lg_disabled.setColorAt(0.82, QColor(230, 230, 230));
_lg_disabled.setColorAt(1, QColor(200, 200, 200));
_offcolor = QColor(255, 255, 255);
_oncolor = QColor(154, 205, 50);
_tol = 0;
_borderradius = 12;
_labeloff = NEW QLabel(this);
_background = NEW SwitchBackground(this, _oncolor);
_labelon = NEW QLabel(this);
_circle = NEW SwitchCircle(this, _offcolor);
__btn_move = NEW QPropertyAnimation(this);
__back_move = NEW QPropertyAnimation(this);
__btn_move->setTargetObject(_circle);
__btn_move->setPropertyName("pos");
__back_move->setTargetObject(_background);
__back_move->setPropertyName("size");
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
_labeloff->setText("Off");
_labelon->setText("On");
_labeloff->move(31, 5);
_labelon->move(15, 5);
setFixedSize(QSize(60, 24));
if (style == Style::YESNO)
{
_labeloff->setText("No");
_labelon->setText("Yes");
_labeloff->move(33, 5);
_labelon->move(12, 5);
setFixedSize(QSize(60, 24));
}
else if (style == Style::BOOL)
{
_labeloff->setText("False");
_labelon->setText("True");
_labeloff->move(37, 5);
_labelon->move(12, 5);
setFixedSize(QSize(75, 24));
}
if (style == Style::EMPTY)
{
_labeloff->setText("");
_labelon->setText("");
_labeloff->move(31, 5);
_labelon->move(12, 5);
setFixedSize(QSize(45, 24));
}
_labeloff->setStyleSheet("color: rgb(120, 120, 120); font-weight: bold;");
_labelon->setStyleSheet("color: rgb(255, 255, 255); font-weight: bold;");
_background->resize(20, 20);
_background->move(2, 2);
_circle->move(2, 2);
}
SwitchButton::~SwitchButton()
{
delete _circle;
delete _background;
delete _labeloff;
delete _labelon;
delete __btn_move;
delete __back_move;
}
void SwitchButton::paintEvent(QPaintEvent*)
{
QPainter* painter = new QPainter;
painter->begin(this);
painter->setRenderHint(QPainter::Antialiasing, true);
QPen pen(Qt::NoPen);
painter->setPen(pen);
painter->setBrush(_pencolor);
painter->drawRoundedRect(0, 0
, width(), height()
, 12, 12);
painter->setBrush(_lg);
painter->drawRoundedRect(1, 1
, width() - 2, height() - 2
, 10, 10);
painter->setBrush(QColor(210, 210, 210));
painter->drawRoundedRect(2, 2
, width() - 4, height() - 4
, 10, 10);
if (_enabled)
{
painter->setBrush(_lg2);
painter->drawRoundedRect(3, 3
, width() - 6, height() - 6
, 7, 7);
}
else
{
painter->setBrush(_lg_disabled);
painter->drawRoundedRect(3, 3
, width() - 6, height() - 6
, 7, 7);
}
painter->end();
}
void SwitchButton::mousePressEvent(QMouseEvent*)
{
if (!_enabled)
return;
__btn_move->stop();
__back_move->stop();
__btn_move->setDuration(_duration);
__back_move->setDuration(_duration);
int hback = 20;
QSize initial_size(hback, hback);
QSize final_size(width() - 4, hback);
int xi = 2;
int y = 2;
int xf = width() - 22;
if (_value)
{
final_size = QSize(hback, hback);
initial_size = QSize(width() - 4, hback);
xi = xf;
xf = 2;
}
__btn_move->setStartValue(QPoint(xi, y));
__btn_move->setEndValue(QPoint(xf, y));
__back_move->setStartValue(initial_size);
__back_move->setEndValue(final_size);
__btn_move->start();
__back_move->start();
// Assigning new current value
_value = !_value;
emit valueChanged(_value);
}
void SwitchButton::setEnabled(bool flag)
{
_enabled = flag;
_circle->setEnabled(flag);
_background->setEnabled(flag);
if (flag)
_labelon->show();
else
{
if (value())
_labelon->show();
else
_labelon->hide();
}
QWidget::setEnabled(flag);
}
void SwitchButton::setDuration(int time)
{
_duration = time;
}
void SwitchButton::setValue(bool flag)
{
if (flag == value())
return;
else
{
_value = flag;
_update();
setEnabled(_enabled);
}
}
bool SwitchButton::value() const
{
return _value;
}
void SwitchButton::_update()
{
int hback = 20;
QSize final_size(width() - 4, hback);
int y = 2;
int xf = width() - 22;
if (_value)
{
final_size = QSize(hback, hback);
xf = 2;
}
_circle->move(QPoint(xf, y));
_background->resize(final_size);
}
SwitchButton::SwitchBackground::SwitchBackground(QWidget* parent, QColor color, bool rect)
: QWidget(parent)
, _rect(rect)
, _borderradius(12)
, _color(color)
, _pencolor(QColor(170, 170, 170))
{
setFixedHeight(20);
_lg = QLinearGradient(0, 25, 70, 0);
_lg.setColorAt(0, QColor(154, 194, 50));
_lg.setColorAt(0.25, QColor(154, 210, 50));
_lg.setColorAt(0.95, QColor(154, 194, 50));
_lg_disabled = QLinearGradient(0, 25, 70, 0);
_lg_disabled.setColorAt(0, QColor(190, 190, 190));
_lg_disabled.setColorAt(0.25, QColor(230, 230, 230));
_lg_disabled.setColorAt(0.95, QColor(190, 190, 190));
if (_rect)
_borderradius = 0;
_enabled = true;
}
SwitchButton::SwitchBackground::~SwitchBackground()
{
}
void SwitchButton::SwitchBackground::paintEvent(QPaintEvent*)
{
QPainter* painter = new QPainter;
painter->begin(this);
painter->setRenderHint(QPainter::Antialiasing, true);
QPen pen(Qt::NoPen);
painter->setPen(pen);
if (_enabled)
{
painter->setBrush(QColor(154, 190, 50));
painter->drawRoundedRect(0, 0
, width(), height()
, 10, 10);
painter->setBrush(_lg);
painter->drawRoundedRect(1, 1, width()-2, height()-2, 8, 8);
}
else
{
painter->setBrush(QColor(150, 150, 150));
painter->drawRoundedRect(0, 0
, width(), height()
, 10, 10);
painter->setBrush(_lg_disabled);
painter->drawRoundedRect(1, 1, width() - 2, height() - 2, 8, 8);
}
painter->end();
}
void SwitchButton::SwitchBackground::setEnabled(bool flag)
{
_enabled = flag;
}
SwitchButton::SwitchCircle::SwitchCircle(QWidget* parent, QColor color, bool rect)
: QWidget(parent)
, _rect(rect)
, _borderradius(12)
, _color(color)
, _pencolor(QColor(120, 120, 120))
{
setFixedSize(20, 20);
_rg = QRadialGradient(static_cast<int>(width() / 2), static_cast<int>(height() / 2), 12);
_rg.setColorAt(0, QColor(255, 255, 255));
_rg.setColorAt(0.6, QColor(255, 255, 255));
_rg.setColorAt(1, QColor(205, 205, 205));
_lg = QLinearGradient(3, 18, 20, 4);
_lg.setColorAt(0, QColor(255, 255, 255));
_lg.setColorAt(0.55, QColor(230, 230, 230));
_lg.setColorAt(0.72, QColor(255, 255, 255));
_lg.setColorAt(1, QColor(255, 255, 255));
_lg_disabled = QLinearGradient(3, 18, 20, 4);
_lg_disabled.setColorAt(0, QColor(230, 230, 230));
_lg_disabled.setColorAt(0.55, QColor(210, 210, 210));
_lg_disabled.setColorAt(0.72, QColor(230, 230, 230));
_lg_disabled.setColorAt(1, QColor(230, 230, 230));
_enabled = true;
}
SwitchButton::SwitchCircle::~SwitchCircle()
{
}
void SwitchButton::SwitchCircle::paintEvent(QPaintEvent*)
{
QPainter* painter = new QPainter;
painter->begin(this);
painter->setRenderHint(QPainter::Antialiasing, true);
QPen pen(Qt::NoPen);
painter->setPen(pen);
painter->setBrush(_pencolor);
painter->drawEllipse(0, 0, 20, 20);
painter->setBrush(_rg);
painter->drawEllipse(1, 1, 18, 18);
painter->setBrush(QColor(210, 210, 210));
painter->drawEllipse(2, 2, 16, 16);
if (_enabled)
{
painter->setBrush(_lg);
painter->drawEllipse(3, 3, 14, 14);
}
else
{
painter->setBrush(_lg_disabled);
painter->drawEllipse(3, 3, 14, 14);
}
painter->end();
}
void SwitchButton::SwitchCircle::setEnabled(bool flag)
{
_enabled = flag;
}
Python 实现(原型;PyQt5)
用法:
switchbtn = SwitchButton(self, "On", 15, "Off", 31, 60)
(...)..py
from PyQt5 import QtWidgets, QtCore, QtGui
class SwitchButton(QtWidgets.QWidget):
def __init__(self, parent=None, w1="Yes", l1=12, w2="No", l2=33, width=60):
super(SwitchButton, self).__init__(parent)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.__labeloff = QtWidgets.QLabel(self)
self.__labeloff.setText(w2)
self.__labeloff.setStyleSheet("""color: rgb(120, 120, 120); font-weight: bold;""")
self.__background = Background(self)
self.__labelon = QtWidgets.QLabel(self)
self.__labelon.setText(w1)
self.__labelon.setStyleSheet("""color: rgb(255, 255, 255); font-weight: bold;""")
self.__circle = Circle(self)
self.__circlemove = None
self.__ellipsemove = None
self.__enabled = True
self.__duration = 100
self.__value = False
self.setFixedSize(width, 24)
self.__background.resize(20, 20)
self.__background.move(2, 2)
self.__circle.move(2, 2)
self.__labelon.move(l1, 5)
self.__labeloff.move(l2, 5)
def setDuration(self, time):
self.__duration = time
def mousePressEvent(self, event):
if not self.__enabled:
return
self.__circlemove = QtCore.QPropertyAnimation(self.__circle, b"pos")
self.__circlemove.setDuration(self.__duration)
self.__ellipsemove = QtCore.QPropertyAnimation(self.__background, b"size")
self.__ellipsemove.setDuration(self.__duration)
xs = 2
y = 2
xf = self.width()-22
hback = 20
isize = QtCore.QSize(hback, hback)
bsize = QtCore.QSize(self.width()-4, hback)
if self.__value:
xf = 2
xs = self.width()-22
bsize = QtCore.QSize(hback, hback)
isize = QtCore.QSize(self.width()-4, hback)
self.__circlemove.setStartValue(QtCore.QPoint(xs, y))
self.__circlemove.setEndValue(QtCore.QPoint(xf, y))
self.__ellipsemove.setStartValue(isize)
self.__ellipsemove.setEndValue(bsize)
self.__circlemove.start()
self.__ellipsemove.start()
self.__value = not self.__value
def paintEvent(self, event):
s = self.size()
qp = QtGui.QPainter()
qp.begin(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing, True)
pen = QtGui.QPen(QtCore.Qt.NoPen)
qp.setPen(pen)
qp.setBrush(QtGui.QColor(120, 120, 120))
qp.drawRoundedRect(0, 0, s.width(), s.height(), 12, 12)
lg = QtGui.QLinearGradient(35, 30, 35, 0)
lg.setColorAt(0, QtGui.QColor(210, 210, 210, 255))
lg.setColorAt(0.25, QtGui.QColor(255, 255, 255, 255))
lg.setColorAt(0.82, QtGui.QColor(255, 255, 255, 255))
lg.setColorAt(1, QtGui.QColor(210, 210, 210, 255))
qp.setBrush(lg)
qp.drawRoundedRect(1, 1, s.width()-2, s.height()-2, 10, 10)
qp.setBrush(QtGui.QColor(210, 210, 210))
qp.drawRoundedRect(2, 2, s.width() - 4, s.height() - 4, 10, 10)
if self.__enabled:
lg = QtGui.QLinearGradient(50, 30, 35, 0)
lg.setColorAt(0, QtGui.QColor(230, 230, 230, 255))
lg.setColorAt(0.25, QtGui.QColor(255, 255, 255, 255))
lg.setColorAt(0.82, QtGui.QColor(255, 255, 255, 255))
lg.setColorAt(1, QtGui.QColor(230, 230, 230, 255))
qp.setBrush(lg)
qp.drawRoundedRect(3, 3, s.width() - 6, s.height() - 6, 7, 7)
else:
lg = QtGui.QLinearGradient(50, 30, 35, 0)
lg.setColorAt(0, QtGui.QColor(200, 200, 200, 255))
lg.setColorAt(0.25, QtGui.QColor(230, 230, 230, 255))
lg.setColorAt(0.82, QtGui.QColor(230, 230, 230, 255))
lg.setColorAt(1, QtGui.QColor(200, 200, 200, 255))
qp.setBrush(lg)
qp.drawRoundedRect(3, 3, s.width() - 6, s.height() - 6, 7, 7)
qp.end()
class Circle(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Circle, self).__init__(parent)
self.__enabled = True
self.setFixedSize(20, 20)
def paintEvent(self, event):
s = self.size()
qp = QtGui.QPainter()
qp.begin(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing, True)
qp.setPen(QtCore.Qt.NoPen)
qp.setBrush(QtGui.QColor(120, 120, 120))
qp.drawEllipse(0, 0, 20, 20)
rg = QtGui.QRadialGradient(int(self.width() / 2), int(self.height() / 2), 12)
rg.setColorAt(0, QtGui.QColor(255, 255, 255))
rg.setColorAt(0.6, QtGui.QColor(255, 255, 255))
rg.setColorAt(1, QtGui.QColor(205, 205, 205))
qp.setBrush(QtGui.QBrush(rg))
qp.drawEllipse(1,1, 18, 18)
qp.setBrush(QtGui.QColor(210, 210, 210))
qp.drawEllipse(2, 2, 16, 16)
if self.__enabled:
lg = QtGui.QLinearGradient(3, 18,20, 4)
lg.setColorAt(0, QtGui.QColor(255, 255, 255, 255))
lg.setColorAt(0.55, QtGui.QColor(230, 230, 230, 255))
lg.setColorAt(0.72, QtGui.QColor(255, 255, 255, 255))
lg.setColorAt(1, QtGui.QColor(255, 255, 255, 255))
qp.setBrush(lg)
qp.drawEllipse(3,3, 14, 14)
else:
lg = QtGui.QLinearGradient(3, 18, 20, 4)
lg.setColorAt(0, QtGui.QColor(230, 230, 230))
lg.setColorAt(0.55, QtGui.QColor(210, 210, 210))
lg.setColorAt(0.72, QtGui.QColor(230, 230, 230))
lg.setColorAt(1, QtGui.QColor(230, 230, 230))
qp.setBrush(lg)
qp.drawEllipse(3, 3, 14, 14)
qp.end()
class Background(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Background, self).__init__(parent)
self.__enabled = True
self.setFixedHeight(20)
def paintEvent(self, event):
s = self.size()
qp = QtGui.QPainter()
qp.begin(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing, True)
pen = QtGui.QPen(QtCore.Qt.NoPen)
qp.setPen(pen)
qp.setBrush(QtGui.QColor(154,205,50))
if self.__enabled:
qp.setBrush(QtGui.QColor(154, 190, 50))
qp.drawRoundedRect(0, 0, s.width(), s.height(), 10, 10)
lg = QtGui.QLinearGradient(0, 25, 70, 0)
lg.setColorAt(0, QtGui.QColor(154, 184, 50))
lg.setColorAt(0.35, QtGui.QColor(154, 210, 50))
lg.setColorAt(0.85, QtGui.QColor(154, 184, 50))
qp.setBrush(lg)
qp.drawRoundedRect(1, 1, s.width() - 2, s.height() - 2, 8, 8)
else:
qp.setBrush(QtGui.QColor(150, 150, 150))
qp.drawRoundedRect(0, 0, s.width(), s.height(), 10, 10)
lg = QtGui.QLinearGradient(5, 25, 60, 0)
lg.setColorAt(0, QtGui.QColor(190, 190, 190))
lg.setColorAt(0.35, QtGui.QColor(230, 230, 230))
lg.setColorAt(0.85, QtGui.QColor(190, 190, 190))
qp.setBrush(lg)
qp.drawRoundedRect(1, 1, s.width() - 2, s.height() - 2, 8, 8)
qp.end()
下面是一个示例:
< code>switch.h:
#pragma once
#include <QtWidgets>
class Switch : public QAbstractButton {
Q_OBJECT
Q_PROPERTY(int offset READ offset WRITE setOffset)
Q_PROPERTY(QBrush brush READ brush WRITE setBrush)
public:
Switch(QWidget* parent = nullptr);
Switch(const QBrush& brush, QWidget* parent = nullptr);
QSize sizeHint() const override;
QBrush brush() const {
return _brush;
}
void setBrush(const QBrush &brsh) {
_brush = brsh;
}
int offset() const {
return _x;
}
void setOffset(int o) {
_x = o;
update();
}
protected:
void paintEvent(QPaintEvent*) override;
void mouseReleaseEvent(QMouseEvent*) override;
void enterEvent(QEvent*) override;
private:
bool _switch;
qreal _opacity;
int _x, _y, _height, _margin;
QBrush _thumb, _track, _brush;
QPropertyAnimation *_anim = nullptr;
};
开关.cpp
:
Switch::Switch(QWidget *parent) : QAbstractButton(parent),
_height(16),
_opacity(0.000),
_switch(false),
_margin(3),
_thumb("#d5d5d5"),
_anim(new QPropertyAnimation(this, "offset", this))
{
setOffset(_height / 2);
_y = _height / 2;
setBrush(QColor("#009688"));
}
Switch::Switch(const QBrush &brush, QWidget *parent) : QAbstractButton(parent),
_height(16),
_switch(false),
_opacity(0.000),
_margin(3),
_thumb("#d5d5d5"),
_anim(new QPropertyAnimation(this, "offset", this))
{
setOffset(_height / 2);
_y = _height / 2;
setBrush(brush);
}
void Switch::paintEvent(QPaintEvent *e) {
QPainter p(this);
p.setPen(Qt::NoPen);
if (isEnabled()) {
p.setBrush(_switch ? brush() : Qt::black);
p.setOpacity(_switch ? 0.5 : 0.38);
p.setRenderHint(QPainter::Antialiasing, true);
p.drawRoundedRect(QRect(_margin, _margin, width() - 2 * _margin, height() - 2 * _margin), 8.0, 8.0);
p.setBrush(_thumb);
p.setOpacity(1.0);
p.drawEllipse(QRectF(offset() - (_height / 2), _y - (_height / 2), height(), height()));
} else {
p.setBrush(Qt::black);
p.setOpacity(0.12);
p.drawRoundedRect(QRect(_margin, _margin, width() - 2 * _margin, height() - 2 * _margin), 8.0, 8.0);
p.setOpacity(1.0);
p.setBrush(QColor("#BDBDBD"));
p.drawEllipse(QRectF(offset() - (_height / 2), _y - (_height / 2), height(), height()));
}
}
void Switch::mouseReleaseEvent(QMouseEvent *e) {
if (e->button() & Qt::LeftButton) {
_switch = _switch ? false : true;
_thumb = _switch ? _brush : QBrush("#d5d5d5");
if (_switch) {
_anim->setStartValue(_height / 2);
_anim->setEndValue(width() - _height);
_anim->setDuration(120);
_anim->start();
} else {
_anim->setStartValue(offset());
_anim->setEndValue(_height / 2);
_anim->setDuration(120);
_anim->start();
}
}
QAbstractButton::mouseReleaseEvent(e);
}
void Switch::enterEvent(QEvent *e) {
setCursor(Qt::PointingHandCursor);
QAbstractButton::enterEvent(e);
}
QSize Switch::sizeHint() const {
return QSize(2 * (_height + _margin), _height + 2 * _margin);
}
main.cpp
:
#include "switch.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QWidget *widget = new QWidget;
widget->setWindowFlags(Qt::FramelessWindowHint);
QHBoxLayout layout;
widget->setLayout(&layout);
Switch *_switch = new Switch;
Switch *_switch2 = new Switch;
_switch2->setDisabled(true);
layout.addWidget(_switch);
layout.addWidget(_switch2);
widget->show();
return a.exec();
}
新材料开关小部件!
< code>style.h
/*
* This is nearly complete Material design Switch widget implementation in qtwidgets module.
* More info: https://material.io/design/components/selection-controls.html#switches
* Copyright (C) 2018 Iman Ahmadvand
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* It is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef STYLE_H
#define STYLE_H
#include <QtCore/qeasingcurve.h>
#define cyan500 QColor("#00bcd4")
#define gray50 QColor("#fafafa")
#define black QColor("#000000")
#define gray400 QColor("#bdbdbd")
Q_DECL_IMPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0); // src/widgets/effects/qpixmapfilter.cpp
namespace Style {
using Type = QEasingCurve::Type;
struct Animation {
Animation() = default;
Animation(Type _easing, int _duration) :easing{ _easing }, duration{ _duration } {
}
Type easing;
int duration;
};
struct Switch {
Switch() :
height{ 36 },
font{ QFont("Roboto medium", 13) },
indicatorMargin{ QMargins(8, 8, 8, 8) },
thumbOnBrush{ cyan500 },
thumbOnOpacity{ 1 },
trackOnBrush{ cyan500 },
trackOnOpacity{ 0.5 },
thumbOffBrush{ gray50 },
thumbOffOpacity{ 1 },
trackOffBrush{ black },
trackOffOpacity{ 0.38 },
thumbDisabled{ gray400 },
thumbDisabledOpacity{ 1 },
trackDisabled{ black },
trackDisabledOpacity{ 0.12 },
textColor{ black },
disabledTextOpacity{ 0.26 },
thumbBrushAnimation{ Animation(Type::Linear, 150) },
trackBrushAnimation{ Animation(Type::Linear, 150) },
thumbPosAniamtion{ Animation(Type::InOutQuad, 150) } {
}
int height;
QFont font;
QMargins indicatorMargin;
QColor thumbOnBrush;
double thumbOnOpacity;
QColor trackOnBrush;
double trackOnOpacity;
QColor thumbOffBrush;
double thumbOffOpacity;
QColor trackOffBrush;
double trackOffOpacity;
QColor thumbDisabled;
double thumbDisabledOpacity;
QColor trackDisabled;
double trackDisabledOpacity;
QColor textColor;
double disabledTextOpacity;
Animation thumbBrushAnimation;
Animation trackBrushAnimation;
Animation thumbPosAniamtion;
};
inline QPixmap drawShadowEllipse(qreal radius, qreal elevation, const QColor& color) {
auto px = QPixmap(radius * 2, radius * 2);
px.fill(Qt::transparent);
{ // draw ellipes
QPainter p(&px);
p.setBrush(color);
p.setPen(Qt::NoPen);
p.setRenderHint(QPainter::Antialiasing, true);
p.drawEllipse(QRectF(0, 0, px.size().width(), px.size().height()).center(), radius - elevation, radius - elevation);
}
QImage tmp(px.size(), QImage::Format_ARGB32_Premultiplied);
tmp.setDevicePixelRatio(px.devicePixelRatioF());
tmp.fill(0);
QPainter tmpPainter(&tmp);
tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
tmpPainter.drawPixmap(QPointF(), px);
tmpPainter.end();
// blur the alpha channel
QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied);
blurred.setDevicePixelRatio(px.devicePixelRatioF());
blurred.fill(0);
{
QPainter blurPainter(&blurred);
qt_blurImage(&blurPainter, tmp, elevation * 4., true, false);
}
tmp = blurred;
return QPixmap::fromImage(tmp);
}
} // namespace Style
#endif // STYLE_H
开关.h
/*
* This is nearly complete Material design Switch widget implementation in qtwidgets module.
* More info: https://material.io/design/components/selection-controls.html#switches
* Copyright (C) 2018-2020 Iman Ahmadvand
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* It is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef SWITCH_H
#define SWITCH_H
#include <QtWidgets>
#include "style.h"
class Animator final : public QVariantAnimation {
Q_OBJECT
Q_PROPERTY(QObject* targetObject READ targetObject WRITE setTargetObject)
public:
Animator(QObject* target, QObject* parent = nullptr);
~Animator() override;
QObject* targetObject() const;
void setTargetObject(QObject* target);
inline bool isRunning() const {
return state() == Running;
}
public slots:
void setup(int duration, QEasingCurve easing = QEasingCurve::Linear);
void interpolate(const QVariant& start, const QVariant& end);
void setCurrentValue(const QVariant&);
protected:
void updateCurrentValue(const QVariant& value) override final;
void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) override final;
private:
QPointer<QObject> target;
};
class SelectionControl : public QAbstractButton {
Q_OBJECT
public:
explicit SelectionControl(QWidget* parent = nullptr);
~SelectionControl() override;
Qt::CheckState checkState() const;
Q_SIGNALS:
void stateChanged(int);
protected:
void enterEvent(QEvent*) override;
void checkStateSet() override;
void nextCheckState() override;
virtual void toggle(Qt::CheckState state) = 0;
};
class Switch final : public SelectionControl {
Q_OBJECT
static constexpr auto CORNER_RADIUS = 8.0;
static constexpr auto THUMB_RADIUS = 14.5;
static constexpr auto SHADOW_ELEVATION = 2.0;
public:
explicit Switch(QWidget* parent = nullptr);
Switch(const QString& text, QWidget* parent = nullptr);
Switch(const QString& text, const QBrush&, QWidget* parent = nullptr);
~Switch() override;
QSize sizeHint() const override final;
protected:
void paintEvent(QPaintEvent*) override final;
void resizeEvent(QResizeEvent*) override final;
void toggle(Qt::CheckState) override final;
void init();
QRect indicatorRect();
QRect textRect();
static inline QColor colorFromOpacity(const QColor& c, qreal opacity) {
return QColor(c.red(), c.green(), c.blue(), qRound(opacity * 255.0));
}
static inline bool ltr(QWidget* w) {
if (nullptr != w)
return w->layoutDirection() == Qt::LeftToRight;
return false;
}
private:
Style::Switch style;
QPixmap shadowPixmap;
QPointer<Animator> thumbBrushAnimation;
QPointer<Animator> trackBrushAnimation;
QPointer<Animator> thumbPosAniamtion;
};
#endif // SWITCH_H
开关.cpp
/*
* This is nearly complete Material design Switch widget implementation in qtwidgets module.
* More info: https://material.io/design/components/selection-controls.html#switches
* Copyright (C) 2018-2020 Iman Ahmadvand
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* It is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "switch.h"
Animator::Animator(QObject* target, QObject* parent) : QVariantAnimation(parent) {
setTargetObject(target);
}
Animator::~Animator() {
stop();
}
QObject* Animator::targetObject() const {
return target.data();
}
void Animator::setTargetObject(QObject* _target) {
if (target.data() == _target)
return;
if (isRunning()) {
qWarning("Animation::setTargetObject: you can't change the target of a running animation");
return;
}
target = _target;
}
void Animator::updateCurrentValue(const QVariant& value) {
Q_UNUSED(value);
if (!target.isNull()) {
auto update = QEvent(QEvent::StyleAnimationUpdate);
update.setAccepted(false);
QCoreApplication::sendEvent(target.data(), &update);
if (!update.isAccepted())
stop();
}
}
void Animator::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) {
if (target.isNull() && oldState == Stopped) {
qWarning("Animation::updateState: Changing state of an animation without target");
return;
}
QVariantAnimation::updateState(newState, oldState);
if (!endValue().isValid() && direction() == Forward) {
qWarning("Animation::updateState (%s): starting an animation without end value", targetObject()->metaObject()->className());
}
}
void Animator::setup(int duration, QEasingCurve easing) {
setDuration(duration);
setEasingCurve(easing);
}
void Animator::interpolate(const QVariant& _start, const QVariant& end) {
setStartValue(_start);
setEndValue(end);
start();
}
void Animator::setCurrentValue(const QVariant& value) {
setStartValue(value);
setEndValue(value);
updateCurrentValue(currentValue());
}
SelectionControl::SelectionControl(QWidget* parent) : QAbstractButton(parent) {
setObjectName("SelectionControl");
setCheckable(true);
}
SelectionControl::~SelectionControl() {
}
void SelectionControl::enterEvent(QEvent* e) {
setCursor(Qt::PointingHandCursor);
QAbstractButton::enterEvent(e);
}
Qt::CheckState SelectionControl::checkState() const {
return isChecked() ? Qt::Checked : Qt::Unchecked;
}
void SelectionControl::checkStateSet() {
const auto state = checkState();
emit stateChanged(state);
toggle(state);
}
void SelectionControl::nextCheckState() {
QAbstractButton::nextCheckState();
SelectionControl::checkStateSet();
}
void Switch::init() {
setFont(style.font);
setObjectName("Switch");
/* setup animations */
thumbBrushAnimation = new Animator{ this, this };
trackBrushAnimation = new Animator{ this, this };
thumbPosAniamtion = new Animator{ this, this };
thumbPosAniamtion->setup(style.thumbPosAniamtion.duration, style.thumbPosAniamtion.easing);
trackBrushAnimation->setup(style.trackBrushAnimation.duration, style.trackBrushAnimation.easing);
thumbBrushAnimation->setup(style.thumbBrushAnimation.duration, style.thumbBrushAnimation.easing);
/* set init values */
trackBrushAnimation->setStartValue(colorFromOpacity(style.trackOffBrush, style.trackOffOpacity));
trackBrushAnimation->setEndValue(colorFromOpacity(style.trackOffBrush, style.trackOffOpacity));
thumbBrushAnimation->setStartValue(colorFromOpacity(style.thumbOffBrush, style.thumbOffOpacity));
thumbBrushAnimation->setEndValue(colorFromOpacity(style.thumbOffBrush, style.thumbOffOpacity));
/* set standard palettes */
auto p = palette();
p.setColor(QPalette::Active, QPalette::ButtonText, style.textColor);
p.setColor(QPalette::Disabled, QPalette::ButtonText, style.textColor);
setPalette(p);
setSizePolicy(QSizePolicy(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Fixed));
}
QRect Switch::indicatorRect() {
const auto w = style.indicatorMargin.left() + style.height + style.indicatorMargin.right();
return ltr(this) ? QRect(0, 0, w, style.height) : QRect(width() - w, 0, w, style.height);
}
QRect Switch::textRect() {
const auto w = style.indicatorMargin.left() + style.height + style.indicatorMargin.right();
return ltr(this) ? rect().marginsRemoved(QMargins(w, 0, 0, 0)) : rect().marginsRemoved(QMargins(0, 0, w, 0));
}
Switch::Switch(QWidget* parent) : SelectionControl(parent) {
init();
}
Switch::Switch(const QString& text, QWidget* parent) : Switch(parent) {
setText(text);
}
Switch::Switch(const QString& text, const QBrush& brush, QWidget* parent) : Switch(text, parent) {
style.thumbOnBrush = brush.color();
style.trackOnBrush = brush.color();
}
Switch::~Switch() {
}
QSize Switch::sizeHint() const {
auto h = style.height;
auto w = style.indicatorMargin.left() + style.height + style.indicatorMargin.right() + fontMetrics().width(text());
return QSize(w, h);
}
void Switch::paintEvent(QPaintEvent*) {
/* for desktop usage we do not need Radial reaction */
QPainter p(this);
const auto _indicatorRect = indicatorRect();
const auto _textRect = textRect();
auto trackMargin = style.indicatorMargin;
trackMargin.setTop(trackMargin.top() + 2);
trackMargin.setBottom(trackMargin.bottom() + 2);
QRectF trackRect = _indicatorRect.marginsRemoved(trackMargin);
if (isEnabled()) {
p.setOpacity(1.0);
p.setPen(Qt::NoPen);
/* draw track */
p.setBrush(trackBrushAnimation->currentValue().value<QColor>());
p.setRenderHint(QPainter::Antialiasing, true);
p.drawRoundedRect(trackRect, CORNER_RADIUS, CORNER_RADIUS);
p.setRenderHint(QPainter::Antialiasing, false);
/* draw thumb */
trackRect.setX(trackRect.x() - trackMargin.left() - trackMargin.right() - 2 + thumbPosAniamtion->currentValue().toInt());
auto thumbRect = trackRect;
if (!shadowPixmap.isNull())
p.drawPixmap(thumbRect.center() - QPointF(THUMB_RADIUS, THUMB_RADIUS - 1.0), shadowPixmap);
p.setBrush(thumbBrushAnimation->currentValue().value<QColor>());
p.setRenderHint(QPainter::Antialiasing, true);
// qDebug() << thumbRect << thumbPosAniamtion->currentValue();
p.drawEllipse(thumbRect.center(), THUMB_RADIUS - SHADOW_ELEVATION - 1.0, THUMB_RADIUS - SHADOW_ELEVATION - 1.0);
p.setRenderHint(QPainter::Antialiasing, false);
/* draw text */
if (text().isEmpty())
return;
p.setOpacity(1.0);
p.setPen(palette().color(QPalette::Active, QPalette::ButtonText));
p.setFont(font());
p.drawText(_textRect, Qt::AlignLeft | Qt::AlignVCenter, text());
} else {
p.setOpacity(style.trackDisabledOpacity);
p.setPen(Qt::NoPen);
// draw track
p.setBrush(style.trackDisabled);
p.setRenderHint(QPainter::Antialiasing, true);
p.drawRoundedRect(trackRect, CORNER_RADIUS, CORNER_RADIUS);
p.setRenderHint(QPainter::Antialiasing, false);
// draw thumb
p.setOpacity(1.0);
if (!isChecked())
trackRect.setX(trackRect.x() - trackMargin.left() - trackMargin.right() - 2);
else
trackRect.setX(trackRect.x() + trackMargin.left() + trackMargin.right() + 2);
auto thumbRect = trackRect;
if (!shadowPixmap.isNull())
p.drawPixmap(thumbRect.center() - QPointF(THUMB_RADIUS, THUMB_RADIUS - 1.0), shadowPixmap);
p.setOpacity(1.0);
p.setBrush(style.thumbDisabled);
p.setRenderHint(QPainter::Antialiasing, true);
p.drawEllipse(thumbRect.center(), THUMB_RADIUS - SHADOW_ELEVATION - 1.0, THUMB_RADIUS - SHADOW_ELEVATION - 1.0);
/* draw text */
if (text().isEmpty())
return;
p.setOpacity(style.disabledTextOpacity);
p.setPen(palette().color(QPalette::Disabled, QPalette::ButtonText));
p.setFont(font());
p.drawText(_textRect, Qt::AlignLeft | Qt::AlignVCenter, text());
}
}
void Switch::resizeEvent(QResizeEvent* e) {
shadowPixmap = Style::drawShadowEllipse(THUMB_RADIUS, SHADOW_ELEVATION, QColor(0, 0, 0, 70));
SelectionControl::resizeEvent(e);
}
void Switch::toggle(Qt::CheckState state) {
if (state == Qt::Checked) {
const QVariant posEnd = (style.indicatorMargin.left() + style.indicatorMargin.right() + 2) * 2;
const QVariant thumbEnd = colorFromOpacity(style.thumbOnBrush, style.thumbOnOpacity);
const QVariant trackEnd = colorFromOpacity(style.trackOnBrush, style.trackOnOpacity);
if (!isVisible()) {
thumbPosAniamtion->setCurrentValue(posEnd);
thumbBrushAnimation->setCurrentValue(thumbEnd);
trackBrushAnimation->setCurrentValue(trackEnd);
} else {
thumbPosAniamtion->interpolate(0, posEnd);
thumbBrushAnimation->interpolate(colorFromOpacity(style.thumbOffBrush, style.thumbOffOpacity), thumbEnd);
trackBrushAnimation->interpolate(colorFromOpacity(style.trackOffBrush, style.trackOffOpacity), trackEnd);
}
} else { // Qt::Unchecked
const QVariant posEnd = 0;
const QVariant thumbEnd = colorFromOpacity(style.thumbOffBrush, style.thumbOffOpacity);
const QVariant trackEnd = colorFromOpacity(style.trackOffBrush, style.trackOffOpacity);
if (!isVisible()) {
thumbPosAniamtion->setCurrentValue(posEnd);
thumbBrushAnimation->setCurrentValue(thumbEnd);
trackBrushAnimation->setCurrentValue(trackEnd);
} else {
thumbPosAniamtion->interpolate(thumbPosAniamtion->currentValue().toInt(), posEnd);
thumbBrushAnimation->interpolate(colorFromOpacity(style.thumbOnBrush, style.thumbOnOpacity), thumbEnd);
trackBrushAnimation->interpolate(colorFromOpacity(style.trackOnBrush, style.trackOnOpacity), trackEnd);
}
}
}
主.cpp
#include "switch.h"
int main(int argc, char *argv[]) {
QApplication application(argc, argv);
QWidget container;
QVBoxLayout mainLayout;
container.setLayout(&mainLayout);
Switch* switch1 = new Switch("SWITCH");
mainLayout.addWidget(switch1);
Switch* switch2 = new Switch("SWITCH");
mainLayout.addWidget(switch2);
switch2->setDisabled(true);
Switch* switch3 = new Switch("SWITCH");
mainLayout.addWidget(switch3);
switch3->setLayoutDirection(Qt::RightToLeft);
Switch* switch4 = new Switch("SWITCH");
mainLayout.addWidget(switch4);
switch4->setLayoutDirection(Qt::RightToLeft);
switch4->setChecked(true);
switch4->setDisabled(true);
QButtonGroup bg;
Switch* item1 = new Switch("ITEM1");
Switch* item2 = new Switch("ITEM2");
bg.addButton(item1);
bg.addButton(item2);
mainLayout.addWidget(item1);
mainLayout.addWidget(item2);
mainLayout.setMargin(100);
container.show();
return application.exec();
}
结果:
导语 自从2009年十月我在博客上写了第一篇QtCreator系列教程到现在,断断续续一共写了四十八篇,涵盖了Qt基础、绘图、数据库、Qt Quick和网络等主要应用方面的内容。虽然其中的内容很基础,但这也正是入门的读者所想要的,现在这个系列的读者已经超过了3万,很感谢大家对我的支持。因为当时开始写教程时并没有想得那么系统,所以就成了想到哪写哪。在现在看来,上来第一篇就是helloworld的编写
我目前在一个Twilio子帐户和一个TwiML应用程序中工作,试图从一个基于web的客户端启动出站呼叫。 我正在使用。浏览器中的设备连接到固定电话。我暴露了一个公共endpoint(使用ngrok),并且TwiML App已成功配置为将呼叫请求POST到endpoint。我正在用
Qt Creator是Qt默认的集成开发环境。它由Qt的开发者们编写提供的。这个集成开发环境能够在大多数的桌面开发平台上使用,例如 Windows/Mac/Linux。我们也已经看到有些用户在嵌入式设备上使用Qt Creator。Qt Creator有着精简的用户界面,可以帮助开发者们高效的完成开发生产。Qt Creator 能够启动你的QtQuick用户界面,也可以用来编译c++代码到你的主机系
C.2.1 国际社区 下面是在线参考的一些国际网址: http://partners.trolltech.com/ http://lists.trolltech.com/qt-interest/ http://doc.trolltech.com/qq/ 可以从 http://doc.trolltech.com 中获取 Qt 的当前版和一些早期版本的在线参考文 档。这个网站也选摘了 Qt 季刊(Qt
问题内容: 在Flutter中是否有任何现成的小部件或从何处开始(https://material.io/guidelines/components/buttons- floating-action-button.html#buttons-floating-action-button-transitions) in Flutter. 问题答案: 这是有关如何使用进行快速拨号的示意图.
1.简介 Qt Demo 是 Qt 套件之一,它包含了大量的演示和示例程序,基本涵盖了 Qt 编程中的 主要类别,将它与 Qt Assistant 结合使用能够收到很好的效果。 2.运行 Qt Demo 要运行 Qt Demo,在 Windows 下,如果是可依次单击【开始】→【(所有)程序】→【Qt SDK by Nokia v2009.03(OpenSource)】→【Qt Demo】;在 X