QT控件大全 三十五 QPianoKeyboard
2017-12-13 11:08
429 查看
效果如图:
核心代码:
QQ:609162385
核心代码:
#ifndef MYPIANOKEYBOARDWIDGET_H #define MYPIANOKEYBOARDWIDGET_H #include <QWidget> class QScrollBar; class MyPianoKeyboardWidget : public QWidget { Q_OBJECT public: MyPianoKeyboardWidget(QWidget *); ~MyPianoKeyboardWidget(); void scrollToCenter(); void emitOutOfRangeNotes(bool); void setRange(int s, int c, int e, bool beQuiet = false); virtual QSize sizeHint () const; signals: void noteOn(int); void noteOff(int); void rangeChanged(int, int, int); protected: virtual void paintEvent(QPaintEvent *event); virtual void mousePressEvent(QMouseEvent *event); virtual void mouseReleaseEvent(QMouseEvent *event); virtual void mouseMoveEvent(QMouseEvent *event); private slots: void sliderPos(int); private: void calculateSize(); int getNoteRangePosition(int note); int getNotePosition(int note); bool isBlack(int note); int getNoteRangeWidth(int note); void noteToRangeRect(int note, QRect &rect); int getNoteFromMousePos(const QPoint &p, bool ignoreY = false); bool getRangeThumbFromMousePos(const QPoint &p, int **thumb); bool updateRangeThumbPosFromMousePos(const QPoint &p); bool fixRangeMarkers(); bool isNoteInRange(int); QSize size; int octaves; int octaveWidth; int centerNote; int scrollOffset; int rangeSelectorSize; int rangeStart; int rangeCenter; int rangeEnd; int viewportWidth; bool doCenter; bool pianoKeyDown; int currentNote; int *selectedRangeThumb; int rangeBoundaryMarkerWidth; bool m_EmitOutOfRangeNotes; QScrollBar *scrollbar; QWidget *parent; }; #endif // MYPIANOKEYBOARDWIDGET_H
#include "mypianokeyboardwidget.h" #include <QPainter> #include <QScrollBar> #include <QRect> #include <QMouseEvent> #include <QPainterPath> #include <QCommonStyle> #include <QStyleOption> #define WWIDTH 23 // full width of white keys #define BWIDTH 15 // width of black keys #define WHEIGHT 80 // length of white keys #define BHEIGHT 50 // length of black keys struct key { int pos; int width; int height; bool isBlack; } octave[12] = { { 0, WWIDTH, WHEIGHT, false}, // c { WWIDTH - BWIDTH/2, BWIDTH, BHEIGHT, true}, // cis { WWIDTH, WWIDTH, WHEIGHT, false}, // d {2*WWIDTH - BWIDTH/2, BWIDTH, BHEIGHT, true}, // dis { 2*WWIDTH, WWIDTH, WHEIGHT, false}, // e { 3*WWIDTH, WWIDTH, WHEIGHT, false}, // f {4*WWIDTH - BWIDTH/2, BWIDTH, BHEIGHT, true}, // fis { 4*WWIDTH, WWIDTH, WHEIGHT, false}, // g {5*WWIDTH - BWIDTH/2, BWIDTH, BHEIGHT, true}, // gis { 5*WWIDTH, WWIDTH, WHEIGHT, false}, // a {6*WWIDTH - BWIDTH/2, BWIDTH, BHEIGHT, true}, // ais { 6*WWIDTH, WWIDTH, WHEIGHT, false} // h }; MyPianoKeyboardWidget::MyPianoKeyboardWidget(QWidget *p) : \ QWidget(p), octaves(10), octaveWidth(0), centerNote(60), scrollOffset(0), rangeSelectorSize(20), rangeStart(57), rangeCenter(60), rangeEnd(65), viewportWidth(0), doCenter(false), pianoKeyDown(false), currentNote(-1), selectedRangeThumb(NULL), rangeBoundaryMarkerWidth(15), m_EmitOutOfRangeNotes(true), parent(p) { scrollbar = new QScrollBar(Qt::Horizontal, this); scrollbar->move(0, rangeSelectorSize+octave[0].height+1); scrollbar->setMinimum(0); scrollbar->setSingleStep(5); scrollbar->setMin 4000 imumHeight(20); calculateSize(); connect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(sliderPos(int))); } MyPianoKeyboardWidget::~MyPianoKeyboardWidget() { } void MyPianoKeyboardWidget::calculateSize() { for(unsigned int i=0; i<12; i++) if(!octave[i].isBlack) octaveWidth += octave[i].width; size.setWidth(octaveWidth*octaves+1); size.setHeight(rangeSelectorSize+octave[0].height+scrollbar->height()+1); } void MyPianoKeyboardWidget::scrollToCenter() { doCenter = true; update(); } void MyPianoKeyboardWidget::emitOutOfRangeNotes(bool e) { m_EmitOutOfRangeNotes = e; } void MyPianoKeyboardWidget::setRange(int s, int c, int e, bool beQuiet) { rangeStart = s-1; rangeCenter = c; rangeEnd = e+1; fixRangeMarkers(); if(!beQuiet) emit rangeChanged(rangeStart+1, rangeCenter, rangeEnd-1); update(); } QSize MyPianoKeyboardWidget::sizeHint() const { return size; } inline int MyPianoKeyboardWidget::getNoteRangePosition(int note) { int _note = note%12; int notePos = octave[_note].pos; if( octave[(_note+23)%12].isBlack ) notePos += BWIDTH/2; return notePos + (note/12)*octaveWidth - scrollOffset; } inline int MyPianoKeyboardWidget::getNotePosition(int note) { int _note = note%12; int notePos = octave[_note].pos; return notePos + (note/12)*octaveWidth - scrollOffset; } inline bool MyPianoKeyboardWidget::isBlack(int note) { return octave[note%12].isBlack; } inline int MyPianoKeyboardWidget::getNoteRangeWidth(int note) { int _note = note%12; int width = octave[_note].width; if( octave[(_note+1)%12].isBlack ) width -= BWIDTH/2; if( octave[(_note+23)%12].isBlack ) width -= BWIDTH/2; return width; } inline void MyPianoKeyboardWidget::noteToRangeRect(int note, QRect &rect) { int noteStart = getNoteRangePosition(note); int noteWidth = getNoteRangeWidth(note); rect.setRect(noteStart, 0, noteWidth, rangeSelectorSize); } void MyPianoKeyboardWidget::paintEvent(QPaintEvent */*event*/) { QPainter painter(this); /* QCommonStyle style; QStyleOption opt; opt.initFrom(this); style.drawPrimitive(QStyle::PE_FrameWindow, &opt, &painter, this); */ painter.fillRect(0, rangeSelectorSize, octaves*octaveWidth, octave[0].height, Qt::white); painter.setPen(Qt::black); if(parent) viewportWidth = parent->width(); else viewportWidth = size.width(); if(parent && parent->width() >= size.width()) { scrollbar->setVisible(false); scrollOffset = 0; }else{ scrollbar->setVisible(true); scrollbar->setMinimumWidth(viewportWidth); scrollbar->setMaximumWidth(viewportWidth); scrollbar->setMaximum(size.width() - viewportWidth); scrollbar->setPageStep(viewportWidth); } if(scrollbar->isVisible() && doCenter) { scrollbar->setValue(getNoteRangePosition(centerNote) - viewportWidth/2 + WWIDTH/2); doCenter = false; } // draw piano keys... for(int i=0; i<octaves; i++) { for(unsigned int j=0; j<12; j++) { int pos = octaveWidth*i + octave[j].pos - scrollOffset; if( (pos >= 0 && pos <= viewportWidth) || (pos < 0 && pos + octave[i].width >= 0) ) { if(octave[j].isBlack) { painter.fillRect(pos, rangeSelectorSize, octave[j].width, octave[j].height, Qt::SolidPattern); }else{ painter.drawRect(pos, rangeSelectorSize, octave[j].width, octave[j].height); if(j == 0) painter.drawText(pos + 8, rangeSelectorSize + octave[j].height - 5, QString("%1").arg(i)); } } } } // highlight currently active key if(currentNote != -1) { int _octave = currentNote/12; int _key = currentNote%12; int _pos = octaveWidth*_octave + octave[_key].pos - scrollOffset; if(isBlack(_key)){ painter.fillRect(_pos, rangeSelectorSize, octave[_key].width, octave[_key].height, Qt::blue); }else{ int _width = getNoteRangeWidth(currentNote); int _pos2 = getNoteRangePosition(currentNote); painter.fillRect(_pos2, rangeSelectorSize, _width, BHEIGHT, Qt::blue); painter.fillRect(_pos, rangeSelectorSize + BHEIGHT, octave[_key].width, octave[_key].height-BHEIGHT, Qt::blue); } } // draw range selector... QRect rStart, rCenter, rEnd; noteToRangeRect(rangeStart, rStart); noteToRangeRect(rangeCenter, rCenter); noteToRangeRect(rangeEnd, rEnd); painter.fillRect(rStart.right(), rStart.top(), rEnd.left()-rStart.right(), rEnd.bottom()-rStart.top(), Qt::lightGray); painter.setPen(Qt::blue); QPainterPath rangeStartPath(rStart.topRight()); rangeStartPath.lineTo(rStart.bottomRight()); rangeStartPath.lineTo(rStart.topRight() - QPoint(rangeBoundaryMarkerWidth, 0)); painter.drawPath(rangeStartPath); painter.fillPath(rangeStartPath, Qt::blue); QPainterPath rangeEndPath(rEnd.topLeft()); rangeEndPath.lineTo(rEnd.topLeft() + QPoint(rangeBoundaryMarkerWidth, 0)); rangeEndPath.lineTo(rEnd.bottomLeft()); painter.drawPath(rangeEndPath); painter.fillPath(rangeEndPath, Qt::blue); painter.fillRect(rCenter, Qt::red); } void MyPianoKeyboardWidget::sliderPos(int p) { scrollOffset = p; update(); } int MyPianoKeyboardWidget::getNoteFromMousePos(const QPoint &p, bool ignoreY) { int _note = -1; if(!ignoreY && (p.y() < rangeSelectorSize || p.y() > rangeSelectorSize + WHEIGHT)) return -1; bool isWhite = false; if(!ignoreY && (p.y() > rangeSelectorSize + BHEIGHT)) isWhite = true; int _octave = (p.x() + scrollOffset)/octaveWidth; int _pos = (p.x() + scrollOffset)%octaveWidth; for(int i=0; i<12; i++) { if(isWhite) { if(!octave[i].isBlack && _pos >= octave[i].pos && _pos < octave[i].pos+octave[i].width) { _note = i; break; } }else{ if(_pos >= octave[i].pos && _pos < octave[i].pos+octave[i].width) { _note = i; break; } } } if(!isWhite && !isBlack(_note) && _pos >= octave[ (_note+1)%12 ].pos && _pos < octave[ (_note+1)%12 ].pos + octave[ (_note+1)%12 ].width) _note++; _note += _octave*12; return _note; } bool MyPianoKeyboardWidget::getRangeThumbFromMousePos(const QPoint &p, int **thumb) { if(p.y() >= rangeSelectorSize) return false; int _pos = getNoteRangePosition(rangeStart) + getNoteRangeWidth(rangeStart) - rangeBoundaryMarkerWidth; int _width = rangeBoundaryMarkerWidth;//getNoteRangeWidth(rangeStart); if( p.x() >= _pos && p.x() < _pos + _width ) { *thumb = &rangeStart; return true; } _pos = getNoteRangePosition(rangeCenter); _width = getNoteRangeWidth(rangeCenter); if( p.x() >= _pos && p.x() < _pos + _width ) { *thumb = &rangeCenter; return true; } _pos = getNoteRangePosition(rangeEnd); _width = rangeBoundaryMarkerWidth;//getNoteRangeWidth(rangeEnd); if( p.x() >= _pos && p.x() < _pos + _width ) { *thumb = &rangeEnd; return true; } return false; } bool MyPianoKeyboardWidget::updateRangeThumbPosFromMousePos(const QPoint &p) { int _note = getNoteFromMousePos(p, true); if(p.y() > rangeSelectorSize) return false; if(_note == -1) return false; if(_note < rangeStart) { rangeStart = _note; return true; }else if(_note > rangeEnd) { rangeEnd = _note; return true; } rangeCenter = _note; return true; } bool MyPianoKeyboardWidget::fixRangeMarkers() { int fixed = 0; if(rangeStart >= rangeCenter) { rangeStart = rangeCenter - 1; fixed++; } if(rangeEnd <= rangeCenter) { rangeEnd = rangeCenter + 1; fixed++; } return fixed > 0 ? true : false; } bool MyPianoKeyboardWidget::isNoteInRange(int note) { return (note > rangeStart && note < rangeEnd) ? true : false; } void MyPianoKeyboardWidget::mousePressEvent(QMouseEvent *event) { currentNote = getNoteFromMousePos(event->pos()); if(currentNote != -1) { pianoKeyDown = true; if(m_EmitOutOfRangeNotes || isNoteInRange(currentNote)) emit noteOn(currentNote); update(); }else{ currentNote = -1; int *thumb = NULL; if(getRangeThumbFromMousePos(event->pos(), &thumb)) { selectedRangeThumb = thumb; }else if(updateRangeThumbPosFromMousePos(event->pos())) { update(); emit rangeChanged(rangeStart+1, rangeCenter, rangeEnd-1); } } } void MyPianoKeyboardWidget::mouseReleaseEvent(QMouseEvent *event) { if(pianoKeyDown) { pianoKeyDown = false; if(m_EmitOutOfRangeNotes || isNoteInRange(currentNote)) emit noteOff(currentNote); currentNote = -1; update(); }else if(selectedRangeThumb != NULL) { emit rangeChanged(rangeStart+1, rangeCenter, rangeEnd-1); selectedRangeThumb = NULL; } } void MyPianoKeyboardWidget::mouseMoveEvent(QMouseEvent *event) { if(pianoKeyDown) { int _note = getNoteFromMousePos(event->pos()); if(_note != currentNote) { if(m_EmitOutOfRangeNotes || isNoteInRange(currentNote)) emit noteOff(currentNote); currentNote = _note; if(m_EmitOutOfRangeNotes || isNoteInRange(currentNote)) emit noteOn(currentNote); update(); } }else if(selectedRangeThumb != NULL) { int _note = getNoteFromMousePos(event->pos(), true); *selectedRangeThumb = _note; if(!fixRangeMarkers()) { //emit rangeChanged(rangeStart, rangeCenter, rangeEnd); update(); } } }源码工程:
QQ:609162385
相关文章推荐
- QT控件大全 八 QNeedleIndicator
- QT控件大全 四十 QNavigationbar
- QT控件大全 三十三 QRoundProgressBar
- QT控件大全 三十九 QVCursorQCircularBar
- QT控件大全 四十四 QColorPicker
- QT控件大全一AnalogWidgets
- QT控件大全 十五 QOpenChart
- QT控件大全 三十七 QColplug
- QT控件大全 三十八 QWidgetKeyboard
- QT控件大全 四十三 QSintCharts
- QT控件,界面设计大全 赶快下载
- QT控件大全 十九 QVCursor
- QT控件大全 二十四 QButtonStyle
- QT控件大全 三十六 QBlackBarButton
- QT控件大全二VirtualKeyboard
- QT控件大全三QLed
- QT控件大全 十 QPower
- QT控件大全 六 QVUMeter
- QT控件大全 十六 QChartXY
- QT控件大全 二十五 QColorWidgets