全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:4188
推到 Plurk!
推到 Facebook!

研究Notepad++原始碼後的心得感想

 
bugmans
高階會員


發表:95
回覆:322
積分:188
註冊:2003-04-12

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-02-04 14:40:49 IP:218.166.xxx.xxx 未訂閱
緣由: 當初在toget軟體報看到介紹,下載試玩後發現有個功能蠻吸引我的 那就是程式碼收納(我不知道正式名稱叫什麼),因為在Visual Studio .Net 2003 也有相同功能,所以我才試著看原始碼來了解其中的機制 http://toget.pchome.com.tw/intro/business_wordprocessing/23486.html 下載: http://sourceforge.net/project/showfiles.php?group_id=95717&package_id=102166 Notepad++使用到Scintilla這個元件,可以到http://www.scintilla.org/看看更詳細的資料 另外我使用doxygen(http://www.doxygen.org)將原始碼轉換成html格式以方便閱讀 感想: 幾天研究下來雖然還沒將程式碼收納的機制研究出來,但也收穫了不少,我先說一下感想 我以前也對RichEdit非常熱衷,總希望為RichEdit多加點功能,但有些特殊功能的參考資 料都少的可憐,常常要在MSDN花很多時間搜尋,或是沒有範例可以看就要自己慢慢測試, 有時候還要用迂迴的方法才能為RichEdit加上新功能 (例如用OLE插入圖http://support.microsoft.com/default.aspx?scid=kb;en-us;220844 個人覺得這方法真的是很麻煩,而且插入後在同一行輸入文字時圖片還會閃爍) 假如要達到msn的插入動態圖背景圖,我想用內建的RichEdit很難做到,否則就是自己重寫 就像Scintilla的發展是因為RichEdit太難用所以才重新寫一個 Development of Scintilla started as an effort to improve the text editor in PythonWin. After being frustrated by problems in the Richedit control used by PythonWin, it looked like the best way forward was to write a new edit control.
附加檔案:64797_pic1.jpg
bugmans
高階會員


發表:95
回覆:322
積分:188
註冊:2003-04-12

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-02-04 15:01:32 IP:218.166.xxx.xxx 未訂閱
心得1:檔案異動偵測 假設在Notepad++開啟C:\test.txt,接下來用其他的文字編輯器修改test.txt或是刪除檔案 回到Notepad++就會出現警告視窗,問使用者是否將資料留下來(UltraEdit也有相同功能) 當初研究出來的時候還很高興,但是搜尋了一下已經有人發表了 http://delphi.ktop.com.tw/topic.php?topic_id=55818 所以本篇文章著重於怎麼找到答案的,原理就是比對檔案修改時間而已 因為我的電腦沒有安裝Visual Studio .NET,所以用UltraEdit的Search/Find In Files來找 目錄設為...\npp.2.7.src , Search Sub Directories選項打勾 一開始先用"exist anymore"這關鍵字搜尋,找到 ...\npp.2.7.src\PowerEditor\src\Notepad_plus.h中的doCloseOrNot
int doCloseOrNot(const char *fn) {
  char phrase[512] = "The file \"";
  strcat(strcat(phrase, fn), "\" doesn't exist anymore. Keep this file in editor ? (Yes keep it, No remove it)");
  return ::MessageBox(_hSelf, phrase, "Save", MB_YESNO | MB_ICONQUESTION | MB_APPLMODAL);
};
再用doCloseOrNot當關鍵字進行搜尋,找到...\npp.2.7.src\PowerEditor\src\Notepad_plus.cpp中的Notepad_plus::checkModifiedDocument()
void Notepad_plus::checkModifiedDocument()
{
  const int NB_VIEW = 2;
  ScintillaEditView * pScintillaArray[NB_VIEW];
  DocTabView * pDocTabArray[NB_VIEW];      // the oder (1.current view 2.non current view) is important
  // to synchronize with "hideCurrentView" function
  pScintillaArray[0] = _pEditView;
  pScintillaArray[1] = getNonCurrentEditView();      pDocTabArray[0] = _pDocTab;
  pDocTabArray[1] = getNonCurrentDocTab();      for (int j = 0 ; j < NB_VIEW ; j++)
  {
    for (int i = (pScintillaArray[j]->getNbDoc()-1) ; i >= 0  ; i--)
    {
      Buffer & docBuf = pScintillaArray[j]->getBufferAt(i);
      docFileStaus fStatus = docBuf.checkFileState();
      pDocTabArray[j]->updateTabItem(i);          if (fStatus == MODIFIED_FROM_OUTSIDE)
      {MODIFIED_FROM_OUTSIDE => 檔案遭外部程式修改
          // If npp is minimized, bring it up to the top
        if (::IsIconic(_hSelf))
          ::ShowWindow(_hSelf, SW_SHOWNORMAL);            if (doReloadOrNot(docBuf.getFileName()) == IDYES)
        {
          pDocTabArray[j]->activate(i);
          // if it's a non current view, make it as the current view
          if (j == 1)
            switchEditViewTo(getNonCurrentView());
          reload(docBuf.getFileName());
        }
        docBuf.updatTimeStamp();
      }
      else if (fStatus == FILE_DELETED)
      {
        if (::IsIconic(_hSelf))
          ::ShowWindow(_hSelf, SW_SHOWNORMAL);            if (doCloseOrNot(docBuf.getFileName()) == IDNO)
        {
          pDocTabArray[j]->activate(i);
          //_pDocTab->closeCurrentDoc();
          if ((pScintillaArray[j]->getNbDoc() == 1) && (_mainWindowStatus & TWO_VIEWS_MASK))
          {
            pDocTabArray[j]->closeCurrentDoc();
            hideCurrentView();
          }
          else
            pDocTabArray[j]->closeCurrentDoc();
        }
      }
          
      bool isReadOnly = pScintillaArray[j]->isCurrentBufReadOnly();
      pScintillaArray[j]->execute(SCI_SETREADONLY, isReadOnly);
      //_pDocTab->updateCurrentTabItem();
    }
  }
}
再用checkFileState當關鍵字搜尋,找到...\npp.2.7.src\PowerEditor\src\ScitillaComponet\Buffer.h
  docFileStaus checkFileState() {
    if (isUntitled(_fullPathName))
    {
      _isReadOnly = false;
      return NEW_DOC;
    }
        if (!PathFileExists(_fullPathName))
    {
      _isReadOnly = false;
      return FILE_DELETED;
    }
    struct _stat buf;
    if (!_stat(_fullPathName, &buf))
    {
      _isReadOnly = (bool)(!(buf.st_mode & _S_IWRITE));
      //比對檔案的修改時間,假如和原來不同代表檔案已被修改過
      if (_timeStamp != buf.st_mtime)
        return MODIFIED_FROM_OUTSIDE;
    }
    return NO_PROBLEM;
  };
再用checkModifiedDocument當關鍵字搜尋,找到這段程式碼 可以知道不是隨時檢查檔案是否被修改,而是使用者切換到Notepad++才檢查 我以前還真的以為UltraEdit有Timer隨時檢查檔案有無異動
    case WM_ACTIVATEAPP :
    {
      NppGUI & nppgui = (NppGUI &)((NppParameters::getInstance())->getNppGUI());
      if (LOWORD(wParam) && nppgui._fileAutoDetection)
      {
        checkModifiedDocument();
        return FALSE;
      }
      return ::DefWindowProc(hwnd, Message, wParam, lParam);
    }
發表人 - bugmans 於 2005/02/04 16:35:09
bugmans
高階會員


發表:95
回覆:322
積分:188
註冊:2003-04-12

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-02-05 20:33:04 IP:218.166.xxx.xxx 未訂閱
心得2:中文輸入法 在...\npp.2.7.src\scintilla\win32\ScintillaWin.cxx有處理輸入法的程式碼,特別節錄出來寫成一個小範例 因為是節錄出來的,所以沒用到的程式碼我都用註解處理,方便和原程式碼作對照,在win2000,winXP還可以輸入unicode的文字並顯示出來 在Unit1.cpp貼上
#include 
#pragma hdrstop    #include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
const int maxLenInputIME = 200;
wchar_t wcs[maxLenInputIME];
static bool onNT = false;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
OldFormWndProc=this->WindowProc;
this->WindowProc=FormWndProc;    OSVERSIONINFO osv = {sizeof(OSVERSIONINFO),0,0,0,0,""};
::GetVersionEx(&osv);
onNT = osv.dwPlatformId == VER_PLATFORM_WIN32_NT;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormWndProc(TMessage& Message)
{
switch (Message.Msg)
  {case WM_IME_STARTCOMPOSITION:
     ImeStartComposition();
     break;
   case WM_IME_ENDCOMPOSITION:
     ImeEndComposition();
     break;
   case WM_IME_COMPOSITION:
     HandleComposition(Message.WParam, Message.LParam);
     break;
   case WM_PAINT:
     ::TextOutW(Form1->Canvas->Handle,10,60,wcs,wcslen(wcs));
     break;
  }
OldFormWndProc(Message);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ImeStartComposition()
{
    // Move IME Window to current caret position
    HIMC hIMC = ::ImmGetContext(Handle);
    //Point pos = LocationFromPosition(currentPos);
    COMPOSITIONFORM CompForm;
    CompForm.dwStyle = CFS_POINT;
    CompForm.ptCurrentPos.x = 10;//pos.x;
    CompForm.ptCurrentPos.y = 10;//pos.y;        ::ImmSetCompositionWindow(hIMC, &CompForm);        // Set font of IME window to same as surrounded text.
    /*if (stylesValid) {
      // Since the style creation code has been made platform independent,
      // The logfont for the IME is recreated here.
      int styleHere = (pdoc->StyleAt(currentPos)) & 31;
      LOGFONT lf = {0,0,0,0,0,0,0,0,0,0,0,0,0,""};
      int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel;
      if (sizeZoomed <= 2)  // Hangs if sizeZoomed <= 1
        sizeZoomed = 2;
      AutoSurface surface(this);
      int deviceHeight = sizeZoomed;
      if (surface) {
        deviceHeight = (sizeZoomed * surface->LogPixelsY()) / 72;
      }
       The negative is to allow for leading
      lf.lfHeight = -(abs(deviceHeight));
      lf.lfWeight = vs.styles[styleHere].bold ? FW_BOLD : FW_NORMAL;
      lf.lfItalic = static_cast(vs.styles[styleHere].italic ? 1 : 0);
      lf.lfCharSet = DEFAULT_CHARSET;
      lf.lfFaceName[0] = '\0';
      if (vs.styles[styleHere].fontName)
        strcpy(lf.lfFaceName, vs.styles[styleHere].fontName);          ::ImmSetCompositionFont(hIMC, &lf);
    }*/
    ::ImmReleaseContext(Handle, hIMC);
    // Caret is displayed in IME window. So, caret in Scintilla is useless.
    //DropCaret();
}
//---------------------------------------------------------------------------
bool IsNT()
{
return onNT;
}
//---------------------------------------------------------------------------
long __fastcall TForm1::HandleComposition(int wParam, int lParam)
{
  long ret;
  if ((lParam & GCS_RESULTSTR) && (IsNT())) {
    HIMC hIMC = ::ImmGetContext(Handle);
    if (hIMC) {
      //const int maxLenInputIME = 200;
      //wchar_t wcs[maxLenInputIME];
      LONG bytes = ::ImmGetCompositionStringW(hIMC,
        GCS_RESULTSTR, wcs, (maxLenInputIME-1)*2);
      int wides = bytes / 2;
      wcs[wides]='\0';
      Form1->Repaint(); 
      /*if (IsUnicodeMode()) {
        char utfval[maxLenInputIME * 3];
        unsigned int len = UTF8Length(wcs, wides);
        UTF8FromUCS2(wcs, wides, utfval, len);
        utfval[len] = '\0';
        AddCharUTF(utfval, len);
      } else {
        char dbcsval[maxLenInputIME * 2];
        int size = ::WideCharToMultiByte(InputCodePage(),
          0, wcs, wides, dbcsval, sizeof(dbcsval) - 1, 0, 0);
        for (int i=0; i
在Unit1.h貼上
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include 
#include 
#include 
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:        // IDE-managed Components
private:        // User declarations
        TWndMethod OldFormWndProc;
        void __fastcall FormWndProc(TMessage& Message);
        void __fastcall ImeStartComposition();
        long __fastcall HandleComposition(int wParam, int lParam);
        void __fastcall TForm1::ImeEndComposition();
public:                // User declarations
        __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
發表人 - bugmans 於 2005/02/05 20:57:02
bugmans
高階會員


發表:95
回覆:322
積分:188
註冊:2003-04-12

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-02-28 17:20:00 IP:218.166.xxx.xxx 未訂閱
趁著放結訓假時再上來發表感想,各位網友如果有什麼想法也可以發表出來    我研究Scintilla原始碼後覺得別人為了彌補RichEdit的不足而重寫一個物件 ,而我只是想辦法為RichEdit添加功能,雖然說重新打造輪子不是個好辦法,但 為RichEdit加上許多難看得補丁更讓我覺得渾身不對勁    http://delphi.ktop.com.tw/topic.php?topic_id=25529 http://delphi.ktop.com.tw/topic.php?topic_id=25456 http://delphi.ktop.com.tw/topic.php?topic_id=39546 這幾篇討論都想為RichEdit加上貼圖的功能,無論用OLE來貼圖或是將圖轉成 RTF字串後插入,甚至用到API Hook,這些方法都不怎麼理想,而且無法貼上jpg 或是gif的圖,也無法設定透明色    我找了其他Third Party如RxRichEdit,infoPower的twwdbrichedit,SynEdit JEDI VCL的TJvCustomRichEdit,我嘗試在google找相關資料最後找的連自己都嫌煩    假如你覺得貼圖還不夠麻煩的話,看看這篇http://delphi.ktop.com.tw/topic.php?TOPIC_ID=65144 RichEdit支援表格的功能要3.0才支援,我在google沒有找到範例,假如有人知道的話可以告訴我 (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/richedit/richeditcontrols/aboutricheditcontrols.asp 其中Rich Edit Version 3.0中有支援Simple tables,注意只是Simple而已)    改用TCppWebBrowser http://delphi.ktop.com.tw/topic.php?topic_id=50859 或許就剩這種方法了吧,無論要插入jpg,動態gif,甚至flash檔案都沒問題 其實Yahoo即時通也是用這種方法,才能將對話框的內容顯示的非常活潑, 我也提供個範例給各位網友參考,雖然只有網頁,但只要將網頁載入到 TCppWebBrowser整個程式介面就變得非常花俏,只要有網頁的基礎就可以為 自己的程式設計漂亮的介面,總比自己動用GDI Api來的方便    範例下載http://delphi.ktop.com.tw/loadfile.php?TOPICID=20628278&CC=461342 bug 網頁中使用JSCookMenu(http://www.cs.ucla.edu/~heng/JSCookMenu/)當作 工具列,只要輸入文字後再開啟工具列會造成文字消失,關閉工具列後文字才 會再出現,我有將這個問題發表在http://dob.tnc.edu.tw/DiscussShow.php?g=70903&s=2902&t=6 靜候網友協助
系統時間:2024-07-05 22:58:26
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!