2010/03/24
ACER AO751h安裝Windows7
[轉載]用OpenOffice Writer製作一本包含封面、目錄、內容及頁數的書
資料來源:用OpenOffice Writer製作一本包含封面、目錄、內容及頁數的書
如何讓OpenOffice Writer自動加入目錄,並製作成包含封面、目錄、內容及頁數的書,是一個讓我困擾已久的問題。以下的方法,是我今天在製作講義時才摸索出來,希望能對各位OpenOffice的愛用者有幫助,如果文件有問題或是有更方便的方法也歡迎提出。
我的目標如下:
1. 封面:不加頁數
2. 目錄:有章節編號及名稱,自動加上頁數
3. 內容:分章、節、小節、subsubsection,從1開始編頁碼
首先附上我製作的例子:odt pdf
以下的說明請參考這兩個例子。
1. 設定頁面樣式
為了讓不同的樣面採用不同型式的頁碼,我們必須先插入不同樣式的頁面。首先開啟一個新的文字文件,一開始預設的頁面樣式為標準。從上方工具列中選取插入=>手動換行,會出現如下圖的視窗。
選取換頁、樣式為標準、變更頁碼為1,再用同一的方法新增一頁,但這次選擇樣式為目錄。但是這樣我們仍然缺少封面,因此再從下圖中紅線框起的部分,按右方的三角形下拉選單,再選擇更多,會出現如下下圖的視窗,雙擊首頁即可將所在的頁面樣式轉換為首頁。
2. 插入頁尾及頁數
從上方工具列中選取插入=>頁尾,選擇標準及目錄就好了,因為我們不想在首頁(封面)顯示頁數。在頁尾的方框中,自上方工具列中選取插入=>欄位指令=>頁碼,即可在除了首頁以外的每一頁最底下顯示頁碼。如果想要讓目錄的頁碼使用別的格式,請在頁碼上按滑鼠右鍵選擇欄位(有時要多按幾次,不容易按到),會出現如下圖的視窗,在這裡面就可以選擇想要的頁碼格式。
3. 變更段落格式
我們在此要先變更一下段落樣式,這些格式是為了給chapter、section、subsection及subsubsection用的(我不知道subsubsection中文要怎麼翻,所以乾脆用英文)。從上方工具列選取工具=>章節編號,會出現如下圖的視窗。我是將標題1設定為第1級的格式,並且在分隔符之前加上第、在之後加上章,這樣顯示出來的結果就會是第x章。相同地,我再將標題2設定給第2級使用,不過這次就不加上文字,而是讓它顯示為x.x。我只有設定到標題4,因為我通常不會用到subsubsection以下的編號。
4. 輸入章節標題
再來就到頁面樣式為標準的頁面中輸入內容,可以先打好章的標題之後再將滑鼠游標移到所在的那行,再從步驟2中第二張圖所標示的地方改變段落樣式。如果是章的標題,則改為標題1;節的標題則改為標題2,依此類推。
5. 插入目錄
最後到頁面樣式為目錄的頁面中,從上方工具列中選取插入=>目錄=>目錄,會出現如下圖的視窗。在第一個分頁中可以決定標題及要顯示到多少級,我將它設定為3級,也就是不顯示subsubsection。另外,我通常會將不允許手動變更去掉,這樣等一下出了任何狀況才可以手動修改。
在第二個分頁中,可以決定顯示的格式。我通常將E#和E之間加入10個空格,讓章節編號和標題間有點距離。
到此為此算是大功告成了。再來我們可以在檔案=>屬性中加入一些此文件的相關資訊(如下圖)。
之後再從檔案=>匯出成PDF檔,將文件轉成pdf檔。在按下匯出之後,會出現如下圖的視窗,我們可以在此決定這個pdf檔相關的性質。
最後,用pdf reader開啟剛才輸出的檔案來看看。因為有加入章節編號的關係,所以pdf檔中已經建立好書籤了,看起來就很專業吧!
2010/03/23
Win7執行BCB6時,發生問題的解決辦法
由於Win7的架構與Vista幾乎是一樣的,所以解決方式應該大同小異
所以參考了
BCB6:
在Vista執行BCB6
2010/03/22
放棄…也算是勇於面對自我吧?
但不知怎麼的,每次的考古題都可以考出很多從沒看過的題目
平均一直都在3x附近排徊…而實務一、實務二也因為長時間沒複習而只有約5x分的水平。
這樣的情況,叫我怎麼去應考呢!!!
猜答案都沒猜對過的經驗來看,放棄應該是明智的選擇吧。
傳說明年度及格分數會調高到75分,看來這張證照離我真是越來越遙遠了呀~~~~~
2010/03/16
[轉載] C++ Builder: Use a mutex to achieve synchronization
看得不是很明白
於是找到另一篇,C++ Builder Developer's Journal / Use a mutex to achieve synchronization
但編排不是很好,所以我有稍微做了一下程式碼的排版,其它內容一字不變地轉載:
January 1998
Use a mutex to achieve synchronization
by Sam Azer
Over the past few months, a few people on the CPB-Thread listserv have asked how to prevent more than one instance of an application from being started. (To subscribe to CPB-Thread, visit www.cobb.com/cpb.) Several people have worked very hard on a variety of answers to this question. It seems, though, that the simplest solution is one suggested by members of Borland's TeamB on their news server: a named mutex. As you know, Windows 95 provides a number of built-in functions for running multiple tasks and threads within a task. Accordingly, a group of Synchronization functions is available to ensure that your tasks and threads are able to work together effectively.
One of the more common problems in a multitasking environment is resource sharing. If you're using a resource--for example, a serial port--you don't want somebody else to start using it before you're finished. The standard solution to this problem is for you to get a mutual exclusion lock (mutex) on the resource. If you're able to get the lock, you can use the resource. If, while trying to lock the resource, you find that somebody else has it--you must wait.
In this article, we'll build a small and very simple function to return true if an instance of a program is already running. To do this, we'll use a simple named mutex. (You can download the code from this article at www.cobb.com/cpb.) Let's start by looking at how you can use a mutex.
Using a named mutex
A mutex is a very simple object. It has a name, access rights, and a state. The name must be unique among all mutex, semaphore, and file-mapping objects. In most cases, the access rights will be MUTEX_ALL_ACCESS. The state can be Owned or Not Owned. If you create a resource that can be used by only one caller at a time, you'll probably also create a mutex for it. In this case, your callers try to open the mutex to see if the resource exists. Once they have a valid handle to the mutex, they use wait functions to gain ownership of the resource and start using it. Wait functions sleep until a mutex isn't owned, then take ownership of it and use the resource. (You can optionally place a time limit on a wait function.) Eventually, the caller will release the mutex, marking it not owned and available to the next caller. In this way, all callers wait to take ownership of the resource when they need it and release it when they're finished. If a caller has no further need for a resource, the mutex handle can be closed.
Once a mutex exists, any tasks trying to create it again will get a handle to it and an error already exists error. If a task ends, all the mutex handles that it owns are closed. When all tasks have closed their handles to a mutex, it's destroyed. Therefore, a single call to the CreateMutex() function is all you need to find out if an instance of an application is already running!
Using CreateMutex()
The CreateMutex() function takes only three parameters: a pointer to a security descriptor, a flag to request immediate ownership, and the name of the mutex to create. It returns a HANDLE. It ignores the pointer to the security descriptor under Windows 95. Under Windows NT, you can get default security settings by passing a NULL pointer. The mutex name is simply any unique null-terminated string (up to MAXPATH characters in length). If the returned HANDLE is null, something undesirable happened. In any case, GetLastError() should return zero to indicate that the mutex was created. A value of ERROR_ALREADY_EXISTS indicates that the mutex already exists. Use SysErrorString() to translate the other error codes into English.
By now you've probably realized that there really isn't much to it--you can very easily detect an existing instance of an application using this method. Listing A shows the source code for one way to do it.
Listing A: Detecting another instance of an application
//--------------------------------------------
#include
#pragma hdrstop
//--------------------------------------------
USEFORM("OneOnlyForm.cpp", Form1);
USERES("OneOnly.res");
//--------------------------------------------
// the name of the mutex for this program
const char *MutexName = "OneOnlyDemo";
//--------------------------------------------
HANDLE CheckInstance( const char *Name )
{
// 1st: create mutex. Request ownership.
HANDLE Mutex = CreateMutex(NULL,true,Name);
// Next, error result - should be zero
int r = GetLastError();
// if r != 0, probably ERROR_ALREADY_EXISTS
if ( r != 0 )
return 0; // disaster or another instance
return Mutex; // else, return the handle.
}
//--------------------------------------------
WINAPI WinMain (HINSTANCE,HINSTANCE,LPSTR, int)
{
HANDLE Mutex = CheckInstance( MutexName );
if ( !Mutex )
{
MessageBox(HInstance, "Another Instance is running!", "Sorry", MB_OK );
ReleaseMutex( Mutex );
return 1;
};
try
{
Application->Initialize();
Application->CreateForm(__classid(TForm1),&Form1);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
return 0;
}
//--------------------------------------------
Wrap up
Do a keyword search for Synchronization in the Win32 (Platform) SDK Help files for detailed information on the functions available for synchronizing--they're quite handy. In many cases the code presented in this article is enough to prevent problems from occurring between two instances of a simple database program. However, for MDI applications you'll probably want to send a message to the original instance. Watch for an article on inter-process communications in a future issue of C++Builder Developer's Journal.
哼…TDataSetProvider…真是被你打敗了呀
一直很不順利,老是出現:
"Table unkown 'TableName'"
於是丟了個SQLMonitor去除錯
結果從SQLMonitor查到的語法是這樣的:
update "TableName" set 'Field' = ? where set 'Field' = ?
[轉載]Delphi ListView基本用法大全
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | //增加項或列(字段) ListView1.Clear; ListView1.Columns.Clear; ListView1.Columns.Add; ListView1.Columns.Add; ListView1.Columns.Add; ListView1.Columns.Items[0].Caption := 'id'; ListView1.Columns.Items[1].Caption := 'type'; ListView1.Columns.Items[2].Caption := 'title'; ListView1.Columns.Items[2].Width := 300; Listview1.ViewStyle := vsreport; Listview1.GridLines := true; //注:此處代碼也可以直接在可視化編輯器中完成,也可寫成以下這樣 begin with listview1 do begin Columns.Add; Columns.Add; Columns.Add; ViewStyle := vsreport; GridLines := true; columns.items[0].caption := ' 進程名'; columns.items[1].caption := '進程ID'; columns.items[2].caption := ' 進程文件路徑'; Columns.Items[0].Width := 100; Columns.Items[1].Width := 100; Columns.Items[2].Width := 150; end end; //增加記錄 with listview1.items.add do begin caption := '1212'; subitems.add('hh1'); subitems.add('hh2'); end; //刪除 listview1.items.delete(0); //從數據庫表裡讀取數據寫入Listview var Titem: Tlistitem; //此處一定要預定義臨時記錄存儲變量. begin ListView1.Items.Clear; with adoquery1 do begin close; sql.Clear; sql.Add('select spmc,jg,sl from kcxs'); Open; ListView1.Items.Clear; while not eof do begin Titem := ListView1.Items.add; Titem.Caption := FieldByName('spmc').Value; Titem.SubItems.Add(FieldByName('sl').Value); Titem.SubItems.Add(FieldByName('jg').Value); next; end; //刪除 ListView1.DeleteSelected; end; end; //如何取得ListView中選中行的某一列的值 procedure TForm1.Button2Click(Sender: TObject); begin ShowMessage(ListView1.Selected.SubItems.Strings[1]); //返回選中行第三列中的值 end; showMessage(listView1.Selected.Caption); //返回選中行第一列的值. //第1列的值: - - > > > ListView1.Selected.Caption //第i列的值(i > 1): - - > > > ListView1.Selected.SubItems.Strings[i] ListView1.Items.Item[1].SubItems.GetText); //取得listview某行某列的值 Edit2.Text := listview1.Items[i].SubItems.strings[0]; //讀第i行第2列 //返回選中行所有子列值.是以回車符分開的,你還要從中剝離出來你要的子列的值。 showMessage(ListView1.Selected.SubItems.GetText); //ListView 簡單排序的實現 //ListView 排序 //怎樣實現單擊一下按升序,再單擊一下按降序。 function CustomSortProc(Item1, Item2: TListItem; ColumnIndex: integer): integer; stdcall; begin if ColumnIndex = 0 then Result := CompareText(Item1.Caption, Item2.Caption) else Result := CompareText(Item1.SubItems[ColumnIndex - 1], Item2.SubItems[ColumnIndex - 1]) end; procedure TFrmSrvrMain.ListView1ColumnClick(Sender: TObject; Column: TListColumn); begin ListView1.CustomSort(@CustomSortProc, Column.Index); end; //=============================================================== //增加 i := ListView1.Items.Count; with ListView1 do begin ListItem := Items.Add; ListItem.Caption := IntToStr(i); ListItem.SubItems.Add('第 ' + IntToStr(i) + ' 行'); ListItem.SubItems.Add(' 第三列內容'); end; //按標題刪除 for i := ListView1.Items.Count - 1 downto 0 do if ListView1.Items[i].Caption = Edit1.Text then begin ListView1.Items.Item[i].Delete(); //刪除當前選中行 end; //選中一行 if ListView1.Selected <> nil then Edit1.Text := ListView1.Selected.Caption; // listview1.Items[Listview1.Items.Count -1].Selected := True; // listview1.Items[Listview1.Items.Count -1].MakeVisible(True); procedure TForm1.Button2Click(Sender: TObject); // 選擇第一條 begin listview1.SetFocus; listview1.Items[0].Selected := True; end; procedure TForm1.Button1Click(Sender: TObject); // 選擇最後一條 begin listview1.SetFocus; listview1.Items[Listview1.Items.Count - 1].Selected := True; end; //這是個通用的過程 procedure ListViewItemMoveUpDown(lv: TListView; Item: TListItem; MoveUp, SetFocus: Boolean); var DestItem: TListItem; begin if (Item = nil) or ((Item.Index - 1 <> = lv.Items.Count) and (not MoveUp)) then Exit; lv.Items.BeginUpdate; try if MoveUp then DestItem := lv.Items.Insert(Item.Index - 1) else DestItem := lv.Items.Insert(Item.Index + 2); DestItem.Assign(Item); lv.Selected := DestItem; Item.Free; finally lv.Items.EndUpdate; end; if SetFocus then lv.SetFocus; DestItem.MakeVisible(False); end; //此為調用過程,可以任意指定要移動的Item,下面是當前(Selected)Item ListViewItemMoveUpDown(ListView1, ListView1.Selected, True, True); //上移 ListViewItemMoveUpDown(ListView1, ListView1.Selected, False, True); //下移 //TListView組件使用方法 //引用CommCtrl單元 procedure TForm1.Button1Click(Sender: TObject); begin ListView_DeleteColumn(MyListView.Handle, i); //i是要刪除的列的序號,從0開始 end; //用LISTVIEW顯示表中的信息: procedure viewchange(listv: tlistview; table: tcustomadodataset; var i: integer); begin tlistview(listv).Items.BeginUpdate; {listv:listview名} try tlistview(listv).Items.Clear; with table do {table or query名} begin active := true; first; while not eof do begin listitem := tlistview(listv).Items.add; listitem.Caption := trim(table.fields[i].asstring); // listitem.ImageIndex:=8; next; end; end; finally tlistview(listv).Items.EndUpdate; end; end; //ListView使用中的一些要點。以下以一個兩列的ListView為例。 //→ 增加一行: with ListView1 do begin ListItem := Items.Add; ListItem.Caption := ' 第一列內容'; ListItem.SubItems.Add('第二列內容'); end; //→清空ListView1: ListView1.Items.Clear; //→得到當前被選中行的行的行號以及刪除當前行: for i := 0 to ListView1.Items.Count - 1 do if ListView1.Items[i].Selected then //i=ListView1.Selected.index begin ListView1.Items.Delete(i); //刪除當前選中行 end; //當然,ListView有 OnSelectItem事件,可以判斷選擇了哪行,用個全局變量把它賦值出來。 //→讀某行某列的操作: Edit1.Text := listview1.Items[i].Caption; //讀第i行第1列 Edit2.Text := listview1.Items[i].SubItems.strings[0]; //讀第i行第2列 Edit3.Text := listview1.Items[i].SubItems.strings[1]; //讀第i行第3列 //以次類推,可以用循環讀出整列。 //→ 將焦點上移一行: for i := 0 to ListView1.Items.Count - 1 do if (ListView1.Items[i].Selected) and (i > 0) then begin ListView1.SetFocus; ListView1.Items.Item[i - 1].Selected := True; end; //不過在Delphi6 中,ListView多了一個ItemIndex屬性,所以只要 ListView1.SetFocus; ListView1.ItemIndex := 3; //就能設定焦點了。 //Delphi的listview能實現交替顏色麼? procedure TForm1.ListView1CustomDrawItem( Sender: TCustomListView; Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean); var i: integer; begin i := (Sender as TListView).Items.IndexOf(Item); if odd(i) then sender.Canvas.Brush.Color := $02E0F0D7 else sender.Canvas.Brush.Color := $02F0EED7; Sender.Canvas.FillRect(Item.DisplayRect(drIcon)); end; |
2010/03/13
讀書心得:蟹工船
上面就是這本書的開場白。
前陣子這本書的內容被翻拍成電影,印象中說是「以詼諧的手法來描述資本主義社會的黑暗」。
覺得可能會很好看,於是去圖書館借。
在排隊排了很長的一段時間,總算是排到了,收到通知的當天就去拿回來看。
剛開始看的時候,就感覺內容好昏暗
看到中期,啊,怎麼這麼可憐
看到後期,機車!怎麼還不反抗!
熬到結局………自己去看吧!(眾人毆)
看完之後的感想是,真的,現在台灣的社會環境和80年前的日本,其實有越來越像的趨勢
資本家越來越來富有,而窮苦的人卻越來越窮苦…
在這本書上可以看到幾種人,以很鮮明的個性表達了現在的各種角色,比方說像是:
書裡的漁、雜工 = 現在的窮忙的現代人 = 羊、鹿…只要是草食動物就行
書裡的薦頭 = 現在的人力仲介 = 誘餌、獅子的僕人?還是動物管理員?
書裡的監督 = 現在的中階幹部 = 鬚狗
而boss呢?還是boss = 獅子
就這樣,一個活生生的食物鏈就在這本書上演了。
其中,有2/3的劇情真的讓人高興不起來,不過卻又讓你有不得不看下去的衝動。
如果,我們的生活結構不去改變,那麼,就真的如同這本書的開場白一樣:
「誒!下地獄囉!」
不過,這樣一來,可憐的就是那些中階幹部了吧!哈哈!
最近開發案子之後的心得
所幸最近BOSS開了新的案子,才有機會將這個方式導入到專案中。
期間遇到的事情也不少,簡單的記錄一下好了。
一、auto_ptr很好用,但出問題時會不知道為什麼發生。(這和自己的功力有關)
二、DataModule Class只做了一個,然後包裝到其它的class中,這個方式會造成很多很多重複new delete的程式碼,比較好的作法應該還是依靠IDE對datamodule的實作,這樣new/delete就會很少出現。
三、承第二點,若未來要改成n-tier的作法,datamodule會改很大,所以也不建議這樣改。
四、想到再繼續寫…
也有一些優點的啦!
一、資料存取時,DB壓力較小
二、因為採用了部分設計模式,大部分程式都靠自己的CLASS解決了,IDE FORM裡的程式碼可以很簡潔。
三、承第二點,IDE FORM專門處理自己的事件,同樣的,商業程式碼也都轉向自己的CLASS來處理,在程式修改上可以很方便的處理。
四、發現用DELPHI來寫時,速度會更快(汗)
五、更加了解DBX的運作過程
六、多玩了DATASNAP的架構
七、一樣,想到再繼續寫…(逃)
2010/03/02
TClientDataSet Run-time時期應注意的地方
說明:
如果不想在Design-time時期設定好TClientDataSet各項參數,可以採用Run-time設計模式。
但如果TClientDataSet是於Design-time時期就已建立,在Run-time時期,該TClientDataSet開啟後,TDataProvider會指向NULL,此時再對該TClientDataSet->Close();,就會發生ACCESS ERROR。
解決方式:
Design-time時期於form表上加入TClientDataSet時,IDE會在 __published 區自動增加TClientDataSet *Temp;
而在Rum-time時,TClientDataSet資料傳輸的主控權即交給IDE自行處理。
所以使用者要擁有較高的管理權,可採自行於程式碼中 new /delete TClientDataSet即可。
2010/3/4 更新
在Help裡查到:
TClientDataSet若是使用SetProvider指向DataSetProvider(Run-time),則TClientDataSet Close()再開前需要再使用SetProvider指向DataSetProvider
動態建立 ClientDataSet 的範例可參考:
ADO and ClientDataSet
2010/03/01
No BOOLEAN field in Firebird?
No BOOLEAN field in Firebird?
There is no built-in boolean field, but you have several options:
1. use char(1)
2. use smallint
3. use domains
Domains are probably the best solution. You can create domain like this:
CREATE DOMAIN BOOLEAN
AS SMALLINT
CHECK (value is null or value in (0, 1));
Later in table definition you can refer to it as a regular datatype.
CREATE TABLE t1
(
C1 VARCHAR(10),
B1 BOOLEAN,
B2 BOOLEAN NOT NULL,
...
);
If you use a connectivity library like OleDB under .Net, you can override the OleDB provider's GetSchema method, so the DataTables you get from queries have native .Net booleans.