PianoCtrl.h
上传用户:fs3633
上传日期:2021-05-14
资源大小:909k
文件大小:25k
源码类别:

midi

开发平台:

Visual C++

  1. #if !defined(AFX_PIANOCTRL_H__C84F71CE_FF29_11D6_865D_0030BD08B6D9__INCLUDED_)
  2. #define AFX_PIANOCTRL_H__C84F71CE_FF29_11D6_865D_0030BD08B6D9__INCLUDED_
  3. #if _MSC_VER > 1000
  4. #pragma once
  5. #endif // _MSC_VER > 1000
  6. // PianoCtrl.h : header file
  7. //
  8. /*
  9.   PianoCtrl.h
  10.   This header file contains the class declaration for the CPianoCtrl and
  11.   its associated classes. The CPianoCtrl class is a custom MFC control 
  12.   representing a piano keyboard display.
  13.   Copyright (C) 2002 Leslie Sanford
  14.   This library is free software; you can redistribute it and/or
  15.   modify it under the terms of the GNU Lesser General Public
  16.   License as published by the Free Software Foundation; either
  17.   version 2.1 of the License, or (at your option) any later version.
  18.   This library is distributed in the hope that it will be useful,
  19.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  21.   Lesser General Public License for more details.
  22.   You should have received a copy of the GNU Lesser General Public
  23.   License along with this library; if not, write to the Free Software
  24.   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
  25.   USA
  26.   Contact: Leslie Sanford (jabberdabber@hotmail.com)
  27.   Last modified: 12/10/2002
  28. */
  29. //---------------------------------------------------------------------
  30. // Dependencies
  31. //---------------------------------------------------------------------
  32. #include <list>         // For holding the list of CPianoCtrlListeners
  33. #include <vector>       // For holding the CPianoKey objects
  34. //---------------------------------------------------------------------
  35. // CPianoCtrlListener class
  36. //
  37. // This class represents an observer class. It receives notification
  38. // for note on and note off events from the CPianoCtrl class. 
  39. //这个CPianoCtrListener类是一个监听类,他接收音符开启和关闭的事件信息
  40. //然后把这些情况通知给CPianoCtrl 类
  41. //---------------------------------------------------------------------
  42. // Forward declaration
  43. class CPianoCtrl;
  44. class CPianoCtrlListener
  45. {
  46. public:
  47.     virtual ~CPianoCtrlListener() {}
  48.     virtual void OnNoteOn(CPianoCtrl &PianoCtrl, 
  49.                           unsigned char NoteId) = 0;
  50.     virtual void OnNoteOff(CPianoCtrl &PianoCtrl,
  51.                            unsigned char NoteId) = 0;
  52. };
  53. //---------------------------------------------------------------------
  54. // CPianoCtrl class
  55. //
  56. // This class represents a piano keyboard. 
  57. //---------------------------------------------------------------------
  58. //
  59. // To use the CPianoCtrl class in a dialog based application, use the 
  60. // following steps:
  61. //
  62. //  1. In the resource editor, place a custom control onto the dialog
  63. //     box.
  64. //
  65. //  2. Set the class name in the custom control's property box to match 
  66. //     the CPianoCtrl's class name.
  67. //
  68. //  3. Add a CPianoCtrl instance variable to the dialog class.
  69. //
  70. //  4. Add a DDX_Control call in the DoDataExchange method in the dialog 
  71. //     class. For example, if your dialog class was named CPianoDlg, the 
  72. //     CPianoCtrl variable was named m_PianoCtrl, and the Id for the
  73. //     control was IDC_PIANOCTRL, you would place the following in the
  74. //     dialog class' DoDataExchange function:
  75. //
  76. //      void CPianoDlg::DoDataExchange(CDataExchange* pDX)
  77. //      {
  78. //       CDialog::DoDataExchange(pDX);
  79. //         //{{AFX_DATA_MAP(CPianoDlg)
  80. //     // NOTE: the ClassWizard will add DDX and DDV calls here
  81. //         //}}AFX_DATA_MAP
  82. //          DDX_Control(pDX, IDC_PIANOCTRL, m_PianoCtrl);
  83. //      }
  84. //
  85. //  5. In the dialog class' OnInitDialog function, initialize the 
  86. //     CPianoCtrl object by calling its Initialize function. Here, you 
  87. //     will pass the desired note range and optionally the note-on 
  88. //     color. 
  89. //
  90. // To use the control dynamically within a dialog box or within a window,
  91. // use the following steps:
  92. //
  93. //  1. Add a CPianoCtrl instance variable to your class. This can be a 
  94. //     pointer to a CPianoCtrl, but if so, you will need to allocate
  95. //     memory for it before using it and deallocate its memory after you
  96. //     are done with it.
  97. //
  98. //  2. Call the CPianoCtrl object's Create function. Here, you will 
  99. //     pass the parent window, the CPianoCtrl's position and size, its
  100. //     Id, and optionally its window style.
  101. //
  102. //  3. Call the CPianoCtrl object's Initialize function. Here, you will 
  103. //     pass the desired note range and optionally the note-on color. 
  104. //
  105. //---------------------------------------------------------------------
  106. //
  107. // Some important notes concerning the CPianoCtrl class:
  108. //
  109. //  It can have up to 128 keys (0 - 127). 
  110. //
  111. //  The range is set with the Initialize method or the SetNoteRange
  112. //  method. You specify the lowest note of the range and the highest 
  113. //  note of the range. The lowest note must be less than the highest 
  114. //  note and both the lowest note and the highest note must be natural.
  115. //
  116. //  The number 0 is considered a C note. As you go up from 0, you are 
  117. //  ascending the chromatic scale. Therefore, 0 equals C, 1 equals C#,
  118. //  2 equals D, etc. After you've reached the B note (the first B note 
  119. //  is number 11), the scale starts over from C.
  120. //
  121. //  To be notified of note on and note off events, derive a class from
  122. //  CPianoCtrlListener. Implement its methods in your derived class 
  123. //  and attach an object of that class to a CPianoCtrl object with the
  124. //  AttachListener method. When the CPianoCtrl object receives note on
  125. //  and note off events, it will notify all of its listeners.
  126. //
  127. //---------------------------------------------------------------------  
  128. //
  129. // CPianoCtrl Member Methods
  130. //
  131. //---------------------------------------------------------------------
  132. //
  133. //  Construction
  134. //
  135. //      CPianoCtrl()      
  136. //
  137. //          Constructs a CPianoCtrl object. It's important to note that
  138. //          the object has not been fully constructed at this point.
  139. //          A call to the Initialize method is still needed to ready
  140. //          the object for use.
  141. //
  142. //      BOOL Create(CWnd *pParentWnd, const RECT &rect, UINT nID, 
  143. //                  DWORD dwStyle = WS_VISIBLE)   
  144. //
  145. //          Creates an CPianoCtrl object dynamically. Returns TRUE if 
  146. //          the operation was successful.
  147. //
  148. //              pParentWnd - Parent window for this control.
  149. //              rect       - Rectangular coordinates for this control.
  150. //              nID        - Identifier for this control.
  151. //              dwStyle    - The window style for this control.   
  152. //
  153. //      BOOL Initialize(unsigned char LowNote, unsigned char HighNote,
  154. //                      COLORREF NoteOnColor = DEF_NOTE_ON_COLOR)
  155. //
  156. //          Initializes this control. Returns true if the operation was
  157. //          successful.
  158. //
  159. //              LowNote     - The lowest note on the keyboard. Must be 
  160. //                            less than the highest note.
  161. //              HighNote    - The highest note on the keyboard. Must be 
  162. //                            less than MAX_NOTE_COUNT.
  163. //              NoteOnColor - The color used to indicate that a key is 
  164. //                            is being played.
  165. //
  166. //---------------------------------------------------------------------
  167. //
  168. //  Operations
  169. //
  170. //      void NoteOn(COLORREF NoteOnColor, unsigned char NoteId)
  171. //      void NoteOn(unsigned char NoteId)
  172. //
  173. //          Turns a note on. 
  174. //
  175. //              NoteOnColor - The color indicating that this key is 
  176. //                            being played.
  177. //              NoteId      - The note to play.       
  178. //
  179. //      void NoteOff(unsigned char NoteId)
  180. //
  181. //          Turns a note off.
  182. //
  183. //              NoteId - The note to stop playing. 
  184. //
  185. //      void AttachListener(CPianoCtrlListener &Listener)
  186. //      void DetachListener(CPianoCtrlListener &Listener)
  187. //
  188. //          Attaches/Detaches CPianoCtrlListener objects. When an 
  189. //          CPianoCtrlListener object is attached to a CPianoCtrl 
  190. //          object, the CPianoCtrl object will notify it when note-on 
  191. //          and note-off events occur.
  192. //
  193. //              Listener - The CPianoCtrlListener to attach/detach.
  194. //
  195. //---------------------------------------------------------------------
  196. //
  197. //  Attributes
  198. //
  199. //      unsigned char GetLowNote() const
  200. //
  201. //          Returns the lowest note for this CPianoCtrl object.      
  202. //
  203. //      unsigned char GetHighNote() const
  204. //
  205. //          Returns the highest note for this CPianoCtrl object.
  206. //
  207. //      BOOL SetNoteRange(unsigned char LowNote, 
  208. //                        unsigned char HighNote)
  209. //      
  210. //          Sets the note range for this CPianoCtrl object. Returns
  211. //          TRUE if the operation was successful.
  212. //
  213. //              LowNote  - The lowest note on the keyboard. Must be 
  214. //                         less than the highest note.
  215. //              HighNote - The highest note on the keyboard. Must be 
  216. //                         less than MAX_NOTE_COUNT.
  217. //
  218. //      COLORREF GetNoteOnColor() const
  219. //
  220. //          Returns the color that indicates a key is being played.
  221. //
  222. //      void SetNoteOnColor(COLORREF NoteOnColor) 
  223. //
  224. //          Sets the color to indicate a key is being played.
  225. //
  226. //              NoteOnColor - The color indicating that a key is 
  227. //                            being played.  
  228. //   
  229. //---------------------------------------------------------------------
  230. class CPianoCtrl : public CWnd
  231. {
  232. public:
  233.     // Construction/Destruction
  234. CPianoCtrl();
  235.     virtual ~CPianoCtrl();
  236.     // Creates the CPianoCtrl 
  237.     BOOL Create(CWnd *pParentWnd, const RECT &rect, UINT nID, 
  238.                 DWORD dwStyle = WS_VISIBLE);
  239.     // Initializes the CPianoCtrl - must be called before this 
  240.     // CPianoCtrl object can be used.
  241.     BOOL Initialize(unsigned char LowNote, unsigned char HighNote,
  242.                     COLORREF NoteOnColor = DEF_NOTE_ON_COLOR);
  243.     // Turns note on//开启音符的函数
  244.     void NoteOn(unsigned char NoteId, COLORREF NoteOnColor);
  245.     void NoteOn(unsigned char NoteId);
  246.     // Turns note off//关闭音符的函数
  247.     void NoteOff(unsigned char NoteId);
  248.     // Attach/Detach CPianoCtrlListener objects
  249.     void AttachListener(CPianoCtrlListener &Listener);
  250.     void DetachListener(CPianoCtrlListener &Listener);
  251.     //
  252.     // Accessors/Mutators
  253.     //
  254.     unsigned char GetLowNote() const { return m_LowNote; }
  255.     unsigned char GetHighNote() const { return m_HighNote; }
  256.     BOOL SetNoteRange(unsigned char LowNote, unsigned char HighNote);
  257.     COLORREF GetNoteOnColor() const { return m_NoteOnColor; }
  258.     void SetNoteOnColor(COLORREF NoteOnColor) 
  259.         { m_NoteOnColor = NoteOnColor; }
  260. // Private functions
  261. private:
  262.     bool IsNoteNatural(unsigned char Note);
  263.     int GetNaturalNoteCount();
  264.     double GetUnitLength();
  265.     void CreatePianoKeys();
  266.     void DestroyPianoKeys();
  267.     int FindKey(CPoint &point);
  268.     // Notify CPianoCtrlListener objects that a note on/off event has
  269.     // occurred.
  270.     void NotifyNoteOn(unsigned char NoteId);
  271.     void NotifyNoteOff(unsigned char NoteId);
  272.     // Register this control's window class注册这个控件的窗口类
  273.     static void RegisterWindowClass();
  274.     //
  275.     // Copying not allowed
  276.     //
  277.     CPianoCtrl(const CPianoCtrl &PianoCtrl);
  278.     CPianoCtrl &operator = (const CPianoCtrl &PianoCtrl);
  279. // Private classes
  280. private:
  281.     //------------------------------------------------------------------
  282.     // Piano key classes
  283.     //
  284.     // The following classes represent the keys on the CPianoCtrl class. 
  285.     //
  286.     //------------------------------------------------------------------
  287.     //
  288.     // To understand how these classes work, first imagine a piano 
  289.     // keyboard display with a range of 12 keys from C to B:
  290.     //
  291.     //                  ----------------------
  292.     //                  | | || | | | || || | |
  293.     //                  | |_||_| | |_||_||_| |
  294.     //                  |  |  |  |  |  |  |  |
  295.     //                  ----------------------
  296.     //
  297.     // We can divide the keys into 4 types:
  298.     //
  299.     //                  ----------------------
  300.     //                  | | || | | | || || | |
  301.     //                  | |_||_| | |_||_||_| |
  302.     //                  |  |  |  |  |  |  |  |
  303.     //                  ----------------------
  304.     //                  /|      /|
  305.     //                   |        | 
  306.     //
  307.     //                  White key left (C and F)
  308.     //
  309.     //
  310.     //                  ----------------------
  311.     //                  | | || | | | || || | |
  312.     //                  | |_||_| | |_||_||_| |
  313.     //                  |  |  |  |  |  |  |  |
  314.     //                  ----------------------
  315.     //                     /|      /| /|
  316.     //                      |        |   |
  317.     //
  318.     //                White key middle (D, G, and A)
  319.     //
  320.     //
  321.     //                  ----------------------
  322.     //                  | | || | | | || || | |
  323.     //                  | |_||_| | |_||_||_| |
  324.     //                  |  |  |  |  |  |  |  |
  325.     //                  ----------------------
  326.     //                        /|          /| 
  327.     //                         |            |
  328.     //
  329.     //                  White key right (E and B)
  330.     //
  331.     //
  332.     //                     |  |     |  |  |
  333.     //                    |/|/   |/|/|/
  334.     //                  ----------------------
  335.     //                  | | || | | | || || | |
  336.     //                  | |_||_| | |_||_||_| |
  337.     //                  |  |  |  |  |  |  |  |
  338.     //                  ----------------------
  339.     //                 
  340.     //            Black key (C#, D#, F#, G#, and A#)
  341.     //
  342.     //
  343.     // There is also a fifth type of key. This is a special key used 
  344.     // when certain ranges are set. For example, look at a range of keys
  345.     // from C to C one octave higher:
  346.     //
  347.     //                  ------------------------
  348.     //                  | | || | | | || || | | | |
  349.     //                  | |_||_| | |_||_||_| | |_|
  350.     //                  |  |  |  |  |  |  |  |  |
  351.     //                  -------------------------
  352.     //
  353.     // A problem occurs because we have half of a black key dangling off
  354.     // the side of the keyboard. This really isn't acceptable, so we 
  355.     // need an additional key to take care of this special case, the
  356.     // white full key:
  357.     //
  358.     //                  -------------------------
  359.     //                  | | || | | | || || | |  |
  360.     //                  | |_||_| | |_||_||_| |  |
  361.     //                  |  |  |  |  |  |  |  |  |
  362.     //                  -------------------------
  363.     //                                        /|
  364.     //                                         |
  365.     //
  366.     //                        White full key
  367.     //
  368.     // The white full key takes care of those cases in which there would
  369.     // otherwise be a black key chopped in half.
  370.     //
  371.     // The five types of piano keys are each represented by their own 
  372.     // class. Each class knows how to draw itself so that it has the 
  373.     // proper shape on the piano keyboard. All of the classes derive 
  374.     // from one parent class called CPianoKey. This class provides the 
  375.     // interface for all piano key classes.
  376.     //
  377.     // The CPianoCtrl class only allows ranges that begin and end with 
  378.     // natural notes (white keys). This was a judgement call on my part.
  379.     // Ranges in which the client chose a sharp/flat key as the lowest
  380.     // or highest note would create a strange situation in which a white
  381.     // key would be chopped in half:
  382.     //
  383.     //                    --------------------
  384.     //                    | || | | | || || | |
  385.     //                    |_||_| | |_||_||_| |
  386.     //                    ||  |  |  |  |  |  |
  387.     //                    --------------------
  388.     //                   /|
  389.     //                    |
  390.     //      
  391.     //              Half-white key?
  392.     //
  393.     // This situation could certainly be dealt with, but if the client
  394.     // specified that C# should be the lowest key, they would have to 
  395.     // deal with the extra half-white key that would actually be the 
  396.     // lowest note, in this case C, and not the one they had specified.
  397.     // I decided this situation was more trouble than it was worth, so
  398.     // I limited the low and high end of the range to natural notes.
  399.     //
  400.     //------------------------------------------------------------------
  401.     //
  402.     // The keys are divided into "units." Units are used to determine 
  403.     // how large to draw each key. The length of a unit is represented 
  404.     // by the total length of the control divided by the number of 
  405.     // natural keys in the range divided by 3. 
  406.     //
  407.     // So if the length of the control is 100 and the number of natural
  408.     // keys in the range is 12, than the unit length would be 2.77778.
  409.     //
  410.     // Here is how the unit length is used:
  411.     //
  412.     // All of the white keys at their longest part take up 3 units:
  413.     //
  414.     //                          ----------
  415.     //                          | | || | |
  416.     //                          | |_||_| |
  417.     //                          |  |  |  |
  418.     //                          ----------
  419.     //                          |<>|<>|<>|
  420.     //                          
  421.     //
  422.     //                         3 Units Long
  423.     //
  424.     // The black keys are 2 units long and the white keys at their 
  425.     // narrowest part are also 2 units long.
  426.     //
  427.     //                         2 Units Long
  428.     //
  429.     //                          / / /
  430.     //                          ----------
  431.     //                          | | || | |
  432.     //                          | |_||_| |
  433.     //                          |  |  |  |
  434.     //                          ----------
  435.     //
  436.     // The unit length is passed to each key object so that it can know
  437.     // how large to draw itself. The position on the control is also 
  438.     // passed to itself so that it can know where to draw itself.
  439.     //
  440.     //-----------------------------------------------------------------
  441.     // Parent piano key class
  442.     class CPianoKey
  443.     {
  444.     public:
  445.         CPianoKey() : m_NoteOnFlag(false) {}
  446.         virtual ~CPianoKey() {}
  447.         // Hit detection 检测按键
  448.         virtual bool IsPointInKey(const CPoint &pt) const = 0;
  449.         // Turns note on/off 开启音符或者关闭音符
  450.         virtual void NoteOn(COLORREF NoteOnColor, CRect &Rect) = 0;
  451.         virtual void NoteOff(CRect &Rect) = 0;
  452.         // Paints this key 绘制琴键
  453.         virtual void Paint(CDC *dc) = 0;
  454.     public:
  455.         // Units per natural key 每一个单位的琴键
  456.         static const int UNIT_PER_NAT_KEY;
  457.         // Determines black keys' width 确定黑键的高度
  458.         static const double BLACK_KEY_OFFSET;
  459.     protected:
  460.         // Function for determining if a point is inside a rectangle.
  461.         // The CRect method PtInRect is inadequate in this context 
  462.         // because it does not count a point on the bottom or on the 
  463.         // right side of the rectangle as being within the rectangle.
  464.         static bool IsPointInRect(const CPoint &pt, const CRect &Rect)
  465.         { 
  466.             return (pt.x >= Rect.left && pt.x <= Rect.right &&
  467.                   pt.y >= Rect.top && pt.y <= Rect.bottom);
  468.         }
  469.     protected:
  470.         bool m_NoteOnFlag;
  471.         COLORREF m_NoteOnColor;
  472.     };
  473.     // CWhiteKeyLeft class
  474.     class CWhiteKeyLeft : public CPianoKey
  475.     {
  476.     public:
  477.         CWhiteKeyLeft(double UnitLength, int Width, double Position);
  478.         bool IsPointInKey(const CPoint &pt) const;
  479.         void NoteOn(COLORREF NoteOnColor, CRect &Rect);
  480.         void NoteOff(CRect &Rect);
  481.         void Paint(CDC *dc);
  482.     private:
  483.         void CalcInvalidRect(CRect &Rect);
  484.     private:
  485.         CRect m_UpperRect;
  486.         CRect m_LowerRect;
  487.     };
  488.     // CWhiteKeyMiddle class
  489.     class CWhiteKeyMiddle : public CPianoKey
  490.     {
  491.     public:
  492.         CWhiteKeyMiddle(double UnitLength, int Width, double Position);
  493.         bool IsPointInKey(const CPoint &pt) const;
  494.         void NoteOn(COLORREF NoteOnColor, CRect &Rect);
  495.         void NoteOff(CRect &Rect);
  496.         void Paint(CDC *dc);
  497.     private:
  498.         void CalcInvalidRect(CRect &Rect);
  499.     private:
  500.         CRect m_UpperRect;
  501.         CRect m_LowerRect;
  502.     };
  503.     // CWhiteKeyRight class
  504.     class CWhiteKeyRight : public CPianoKey
  505.     {
  506.     public:
  507.         CWhiteKeyRight(double UnitLength, int Width, double Position);
  508.         bool IsPointInKey(const CPoint &pt) const;
  509.         void NoteOn(COLORREF NoteOnColor, CRect &Rect);
  510.         void NoteOff(CRect &Rect);
  511.         void Paint(CDC *dc);
  512.     private:
  513.         void CalcInvalidRect(CRect &Rect);
  514.     private:
  515.         CRect m_UpperRect;
  516.         CRect m_LowerRect;
  517.     };
  518.     // CWhiteKeyFull class
  519.     class CWhiteKeyFull : public CPianoKey
  520.     {
  521.     public:
  522.         CWhiteKeyFull(double UnitLength, int Width, double Position);
  523.         bool IsPointInKey(const CPoint &pt) const;
  524.         void NoteOn(COLORREF NoteOnColor, CRect &Rect);
  525.         void NoteOff(CRect &Rect);
  526.         void Paint(CDC *dc);
  527.     private:
  528.         CRect m_Rect;
  529.     };
  530.     // CBlackKey class
  531.     class CBlackKey : public CPianoKey
  532.     {
  533.     public:
  534.         CBlackKey(double UnitLength, int Width, double Position);
  535.         bool IsPointInKey(const CPoint &pt) const;
  536.         void NoteOn(COLORREF NoteOnColor, CRect &Rect);
  537.         void NoteOff(CRect &Rect);
  538.         void Paint(CDC *dc);
  539.     private:
  540.         CRect m_Rect;
  541.     };
  542. // Public attributes
  543. public:
  544.     // The class name of this control
  545.     static const char CLASS_NAME[];
  546.     // Default color used for indicating that a note is being played
  547.     static const COLORREF DEF_NOTE_ON_COLOR;
  548.     // The maximum number of notes this piano control can have
  549.     static const int MAX_NOTE_COUNT;
  550.     // Note identifiers //音符标示符
  551.     enum NoteId { C, C_SHARP, D, D_SHARP, E, F, F_SHARP, G, G_SHARP, A, 
  552.                   A_SHARP, B };
  553.     // Table of note identifiers //音符标示表
  554.     static const int NOTE_TABLE[];
  555. // Private attributes
  556. private:
  557.     // For protecting access to the list of listeners
  558.     CRITICAL_SECTION m_CriticalSection;
  559.     // Color indicating a key is being played 用颜色来标示一个键开始弹奏
  560.     COLORREF m_NoteOnColor;
  561.     // Lenght of this control 这个控件的长度
  562.     int m_Length;
  563.     // Width of this control 这个控件的宽度
  564.     int m_Width;            
  565.     
  566.     // Low note of the range 低音符的排列
  567.     unsigned char m_LowNote;
  568.     // High note of the range 高音符的排列
  569.     unsigned char m_HighNote;      
  570.     // Unit length for each key 每个键的单位长度
  571.     double m_UnitLength;
  572.     // Flag for indicating whether or not this object has been 
  573.     // intialized.无论这个对象都有没有初始化,都用标记来标示它
  574.     bool m_IsInitialized;
  575.     // Flag for indicating whether or not this window has captured the 
  576.     // mouse. 无论Windows窗口有没有获得鼠标动作,都用标记来标示它
  577.     bool m_HasCapture;    
  578.     // Collection of piano key objects 搜索琴键的对象
  579.     std::vector<CPianoKey *> m_Keys;
  580.     // The current active key (triggered by the mouse)
  581.     //当前活动的琴键,也几是鼠标触发的琴键
  582.     int m_CurrKey;
  583.     // Collection of piano control listeners
  584.     std::list<CPianoCtrlListener *> m_Listeners; 
  585.     // Flag for whether or note this custom control's Window class has 
  586.     // been registered.
  587.     static bool REGISTER_FLAG;
  588.     // Messages for range errors 错误的消息队列
  589.     static const CString NOTE_RANGE_ERR;
  590.     static const CString LOW_NOTE_RANGE_ERR;
  591.     static const CString HIGH_NOTE_RANGE_ERR;
  592.     static const CString INVALID_RANGE_ERR;
  593.     static const CString NATURAL_NOTE_ERR;
  594. //----------------------------------------------------------------------
  595. // Wizard generated code 
  596. //----------------------------------------------------------------------
  597. public:
  598. // Overrides
  599. // ClassWizard generated virtual function overrides
  600. //{{AFX_VIRTUAL(CPianoCtrl)
  601. //}}AFX_VIRTUAL
  602. // Generated message map functions
  603. protected:
  604. //{{AFX_MSG(CPianoCtrl)
  605. afx_msg void OnPaint();
  606. afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
  607. afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
  608. afx_msg void OnMouseMove(UINT nFlags, CPoint point);
  609. //}}AFX_MSG
  610. DECLARE_MESSAGE_MAP()
  611. };
  612. /////////////////////////////////////////////////////////////////////////////
  613. //{{AFX_INSERT_LOCATION}}
  614. // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
  615. #endif // !defined(AFX_PIANOCTRL_H__C84F71CE_FF29_11D6_865D_0030BD08B6D9__INCLUDED_)