1. Trang chủ
  2. » Luận Văn - Báo Cáo

bài tập lớn số 7 xây dựng một phần mềm soạn thảo text editor

19 0 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Xây dựng một phần mềm soạn thảo TEXT EDITOR
Tác giả Phạm Bá Độ, Vũ Xuân Thịnh
Người hướng dẫn TS. Đỗ Thị Ngọc Diệp
Trường học Trường Đại học Bách Khoa Hà Nội
Chuyên ngành Cấu trúc dữ liệu và Giải thuật
Thể loại Bài tập lớn
Năm xuất bản 2022
Thành phố Hà Nội
Định dạng
Số trang 19
Dung lượng 366,64 KB

Nội dung

Một Text Editor cơ bản thì cần có các chức năng chính như: nhập ký tự, lưu văn bản, undo, redo…Để giải quyết bài toán trên, nhóm 7 chúng em đưa ra các hướng giải quyết sau cho mỗi yêu cầ

Trang 1

TRƯỜNG ĐẠI HỌC BÁCH KHOA HÀ NỘI

VIỆN ĐIỆN TỬ VIỄN THÔNG

Bộ môn Cấu trúc dữ liệu và Giải thuật

- -BÀI TẬP LỚN SỐ 7

Xây dựng một phần mềm soạn thảo TEXT EDITOR

Giảng viên hướng dẫn: TS Đỗ Thị Ngọc Diệp

Sinh viên thực hiện: Phạm Bá Độ – 20203362

Vũ Xuân Thịnh – 20203596

Lớp: 133323 – ET2100

Hà Nội, 7 – 2022

Trang 2

Bảng danh sách nhóm,công việc được phân công

STT Họ và

Tên

MSSV

Email

Công việc Mức độ

hoàn tành

Ghi ch ú

Xuân

THỊNH

20203596 Thinh.vx203596

@sis.hust.edu.vn

Thiết kế, cài đặt giao diện và các

kỹ thuật liên quan đến chương trình.

Đưa thuật toán Undo/

Redo vào kết hợp trong thuật toán giao diện.

100%

Bá ĐỘ 20203362

do.pb20203362

@sis.hust.edu.vn

Thiết kế và cài đặt thư viện Stack.

Thiết kế và cài đặt thuật toán Undo/Redo.

100%

Trang 3

I.Giới thiệu bài toán

Bài toán: “Xây dựng một phần mềm soạn thảo text editor, có giao diện, cho phép nhập ký tự vào từ bàn phím Cho phép thực hiện chức năng

undo/redo việc nhập ký tự tối đa 10 ký tự”

Text Editor hay Trình soạn thảo văn bản là một trong những công cụ cơ bản giúp mọi người soạn thảo văn bản và lưu văn bản đó Một số ví dụ điển hình của một Text Editor như Microsoft Word, NotePad, Pages… Một Text Editor cơ bản thì cần có các chức năng chính như: nhập ký tự, lưu văn bản, undo, redo…

Để giải quyết bài toán trên, nhóm 7 chúng em đưa ra các hướng giải quyết sau cho mỗi yêu cầu:

 Giao diện: sử dụng Win32 API và ngôn ngữ C++ để tạo giao diện và các chức năng liên quan

 Chức năng undo/redo: Sử dụng cấu trúc dữ liệu Stack để lưu các văn bản dành cho hai chức năng trên

 Định dạng văn bản: văn bản sẽ được lưu với đuôi ‘.txt’

Win32 API là bộ giao diện lập trình ứng dụng (API) cốt lõi của Microsoft có sẵn trong các hệ điều hành Microsoft Windows Để sử dụng bộ giao diện này, chúng em sử dụng ngôn ngữ lập trình C++ và thư viện ‘window.h’ Vì đặc thù của các hàm xây dựng giao diện khá phức tạp và không nằm trong các nội dung chính của bản báo cáo nên chúng em sẽ không trình bày sâu

về phần lập trình giao diện, tuy nhiên các thuật toán Undo/Redo sẽ được phối hợp với các hàm giao diện để có thể tạo ra một chương trình hoàn chỉnh Vì thế khi trình bày cài đặt thuật toán sẽ có những chi tiết thuộc về mặt xử lý giao diện sẽ được ghi chú

Sau đây là cấu trúc chung cho cả chương trình:

Trang 4

Hình 1

No

No

Yes

Yes

Yes

User thao tác làm thay đổi văn bản

Help

Mở file sẵn Soạn văn bản mới

Mở Text Editor Bắt đầu

User muốn save

Save file

User muốn exit

Xử lý undo/redo

Stop

Trang 5

III Mô tả cấu trúc dữ liệu sử dụng

Trong chương trình này, có hai thuật toán quan trọng mà nhóm em chú trọng đó là Undo và Redo Và để có thể sử dụng hai chức năng Undo và Redo thì cần lưu các thay đổi của văn bản, và khi User muốn Undo hay Redo một công việc, thì công việc trước đó sẽ được hoàn lại Vì thế để lưu các công việc này lại theo đúng thứ tự công việc muộn nhất sẽ là công việc được hoàn lại sớm nhất, nhóm em quyết định sử dụng cấu trúc Stack (ngăn xếp)

Stack là một cấu trúc dữ liệu hoạt động theo nguyên tắc Last In First Out, phù hợp với cách lưu dữ liệu mà nhóm em muốn Stack hay Ngăn Xếp hiểu đơn giản là một cấu trúc dữ liệu mà phần tử mới khi được thêm vào sẽ được thêm vào stack và khi lấy ra ta sẽ lấy phần tử ở đỉnh stack (phần tử được thêm vào gần nhất)

Một ví dụ trong thực tế của stack giúp chúng ta có thể dễ hình dung được

đó chính là hộp trụ tròn để đựng các miếng khoai tây chiên tròn Khi muốn cho khoai tây chiên vào trong hộp, ta sẽ cho khoai vào từ đáy hộp cầu đi lên

và khi muốn lấy khoai tây chiên ra thì ta sẽ lấy miếng khoai trên cùng, đó là miếng khoai được bỏ vào cuối cùng

Để có thể sử dụng được cấu trúc này, em tạo riêng thư viện Stack, bao gồm tất cả các hàm khởi tạo và và các hàm để làm việc với Stack Đối với cấu trúc lưu trữ của Stack, nhóm em quyết định sử dụng Singly Linked List (Danh sách liên kết đơn) để lưu các phần tử Mỗi Node của Singly Linked List bao gồm 2 phần: dữ liệu và con trỏ chứa địa chỉ của Node tiếp theo Linked list này sẽ được xây dựng các hàm ra vào để có thể trở thành một Stack Đặc biệt dữ liệu của Node có dạng String của C++ bởi vì văn bản là chuỗi các kỳ tự, vì vậy việc lưu văn bản cho hai chức năng Undo và Redo dưới dạng chuỗi ký tự là cách đơn giản nhất

Dưới đây là cấu trúc đơn giản của một Stack sửu dụng Single Linked List:

Trang 6

Undo/Redo Stack

Hình 2:

IV Thiết kế giải thuật, CTDL

Giải thuật chính trong bài toán là giải thuật cho hai chức năng Undo và Redo Để sử dụng hai chức năng trên thì cần kết hợp cấu trúc ngăn xếp như

đã giải thích bên trên

a Thiết kế sơ bộ:

Hình 3.

Head

Thêm thay đổi vào

Undo/Redo stack

Xuất dữ liệu khi User nhấn Undo/Redo Undo và Redo

Redo Undo

Trang 7

b Thiết kế chi tiết.

Bản chất cách làm việc của Undo và Redo là quay lại công việc vừa thực hiện trước đó, lần lượt cho tới khi đến công việc được thực hiện đầu tiên Đây chính là chức năng chính của cấu trúc Stack: “Vào Sau

Ra Trước” hay “Last In First Out”

Vì vậy chúng em sẽ sử dụng hai Stack là Undo Stack và Redo Stack, mỗi Stack lưu trữ dữ liệu cho từng chức năng cùng tên

Mỗi khi User thực hiện một công việc, nội dung của văn bản cũ sẽ được lưu vào Undo Stack và khi User undo một công việc, công việc

đó sẽ được lưu vào Redo Stack

Trước tiên, chúng ta cần xác định những trường hợp mà khi User thay đổi văn bản thì ta coi đó là một công việc có thể Undo và ta lưu vào Undo Stack (từ giờ ta coi thay đổi đó là một công việc) :

 Khi User mở một File có sẵn, nội dung ban đầu của File đó sẽ được lưu vào Undo Stack

 Khi User xóa bỏ ký tự, nội dung của văn bản trước sẽ được đẩy vào Undo Stack

 Khi User xuống dòng

 Khi User dùng chức năng Redo

Tiếp theo là các trường hợp để lưu vào Redo Stack, vì bản chất của chức năng Redo là hoàn lại những gì User vừa undo, thế nên Redo chỉ

có một trường hợp duy nhất được sử dụng:

 Khi User undo một công việc, nội dung của văn bản trước sẽ được đẩy vào Redo Stack

Một điểm đặc biệt là sau khi Undo/Redo, nếu User thực hiện một công việc với văn bản, khi đó User sẽ không được redo nữa, và để thực hiên điều này thì dữ liệu trong Redo Stack sẽ bị xóa

Từ những phân tích trên, ta vẽ được lưu đồ xác định một thay đổi có phải là công việc hay không:

Trang 8

(Trong lưu đồ sẽ không đề cập đến một số biến , đặc biệt là 2 biến lưu giữ việc User đã sử dụng hai chức năng Undo Và Redo hay không Việc lưu giữ hành động Undo/Redo của User vừa thực hiện sẽ giúp chúng ta xác định được những trường hợp mà khi User thực hiện một thay đổi thì thay đổi đó có được coi là một công việc để lưu vào Undo Stack hay không Tuy nhiên vì tính tổng hợp của lưu đồ nên chúng em sẽ chỉ trình bày phần cài đặt của hai biến này mà không đưa vào lưu đồ)

Yes

Yes

No

Hình 4.

Có sự thay đổi

Văn bản trống Đẩy vào Undo Stack

ND mới ngắn hơn ND cũ/

xuống dòng

User vừa

dùng

Undo/Redo

Trang 9

Từ lưu đồ trên, ta chuyển từng phần sang ngôn ngữ C++ sử dụng API

Win32:

Bảng 1.

Kiểm tra văn bản trống (Nếu văn

bản trống thì ta cần đẩy vào Undo

Stack trạng thái trống này, cụ thể

là một string trống “”.)

if (size == 0 ) {

push ( & file_undo, "" );

old_text = "" ; }

Nội dung mới ngắn hơn nội dung

cũ (User xóa ký tự)

if (old_text length () > size) {

string mydata(data);

push ( & file_undo,old_text); }

User vừa dùng một trong hai chức

năng Undo/Redo (Biến

‘redo_parameter’ và

‘undo_parameter’ sẽ đánh dấu liệu

hành động trươc đó của User có

phải là redo hay undo không)

if (old_text length () < size) {

// if user text more after undo/redo, we need to push old_text into undo

if (redo_parameter == true ) {

push ( & file_undo,old_text); redo_parameter = false ; }

if (undo_parameter == true ) {

push ( & file_undo,old_text); undo_parameter = false ; }

{

User xuống dòng if (data[size - 1 ] == ' \n ' )

{

}

Trang 10

Và dưới đây là chi tiết cài đặt thuật toán trong C++:

Bảng 2.

case EN_UPDATE : // User changes the document

{

saved = false ;

if (size == 0 )

{

push ( & file_undo, "" );

old_text = "" ;

}

size = GetWindowTextLength (hEdit); // Get size of the curent document

char * data = new char [size + 1 ];

GetWindowTextA (hEdit,data,size + 1 );

data[size] = ' \0 ' ;

if (old_text length () > size)

{

string mydata(data);

push ( & file_undo,old_text);

}

if (old_text length () < size)

{

{

push ( & file_undo, string (data));

}

if (redo_parameter == true )

{

push ( & file_undo,old_text);

redo_parameter = false ;

}

if (undo_parameter == true )

{

push ( & file_undo,old_text);

undo_parameter = false ;

}

clear ( & file_redo);

}

// update the old_text

old_text = string(data);

delete[] data;

Trang 11

}

break ;

Đối với việc cài đặt cấu trúc Stack, chúng em cài đặt bằng C++ và sử dụng Singly Linked List với kiểu dữ liệu là ‘String’ trong thư viện “string”

Vì chỉ được tối đa 10 lần Undo/Redo, nên kích thước của Stack chỉ được 10 Node, vì vậy khi ta đẩy công việc vào hai Stack trên, ta cần kiểm tra nếu kích thước của Stack đã bằng 10 thì cần xóa node ở đáy Stack Vì vậy em đã thêm một hàm để xóa node đáy trong thư viện Stack là Leak():

Bảng 3.

string leak (stack *S) {

{

a = a -> next;

} string x = a -> next -> content;

a -> next = NULL ;

}

Tiếp theo là hai lưu đồ để sử dụng hai chức năng là Undo và Redo:

Yes

Undo Stack trống

Không làm gì cả

Đẩy dữ liệu đó vào Redo

Stack Lấy dữ liệu ra và in ra màn

hình

Trang 12

No

Hình 6: Lưu Đồ Redo

Đối với việc cài đặt thư viện Stack, ngoài điểm khác biệt là hàm Leak() đã được nêu bên trên thì còn một thay đổi so với cách cài đặt Stack thông thường đó là trong hàm Push() dùng để đẩy node mới vào Stack, nhóm em thêm một điều kiện nếu chiều dài của Stack đã bằng 10 thì node đáy Stack

sẽ bị đẩy ra nhường chỗ cho node mới, ở đây sử dụng hàm Leak(), giải thuật như sau:

If Length of Stack == 10:

Leak(Stack);

Ngoài ra không có gì khác biệt nên việc cài đặt thư viện Stack sẽ không được trình bày chi tiết trong báo cáo, tuy nhiên việc trình bày các thuật toán của Undo và Redo dưới ngôn ngữ lập trình cụ thể sẽ sử dụng các hàm

Không làm gì

Đẩy dữ liệu vào Undo

stack

Lấy dữ liệu ra và in ra

màn hình

Redo stack trống

Trang 13

của thư viện Stack(“file_stack.h”), khi đó các hàm được sử dụng sẽ được ghi chú

Dưới đây là cài đặt chi tiết cho hai function Undo và Redo trên:

void MainWindow:: redo ()

{

if ( isempty (file_redo) == false ) // if redo stack is empty, we don’t do anything

{

redo_parameter = true ; // keep track of redo condition

size = GetWindowTextLength (hEdit); //get size of the current document

char * undo_data = new char [size + 1 ];

// get the content of the current document

GetWindowTextA (hEdit,undo_data,size + 1 );

// we use dynamic memmories so we need to set last element '\0' to finish the string

undo_data[size] = ' \0 ' ;

string a(undo_data);

// Everytime we redo, we need to push the old text to

'file_undo' so that we can undo what we've just redo

push ( & file_undo,a); // push the old text into Undo Stack, a function of ‘file_stack.h’

string data = pop ( & file_redo); // Get the content for redo from Redo Stack, this is a function of ‘file_stack.h’

old_text = data;

int len = data length ();

char * mydata = new char (len + 1 );

// this is how we conver 'string' into 'char', becasue

SetWindowText don't use 'string' type

strcpy (mydata,data c_str ());

// we use dynamic memmories so we need to set last element '\ 0' to finish the string

mydata[len] = ' \0 ' ;

// display the redo text

SetWindowTextA (hEdit,mydata);

// update size of the text becasue "SetWindowText()" doesn't send EN_UPDATE measage(means we can update size in case : EN_UPDATE)

size = GetWindowTextLength (hEdit);

delete[] mydata;

delete[] undo_data;

}

Trang 14

Bảng 4: Hàm Redo

Bảng 5: Hàm Undo

void MainWindow:: undo ()

{

// Check if the stack 'file_undo'' is empty

if ( isempty (file_undo) == false )

{

// we set undo_parameter to be true so that if user text anything after undo, we know to push the old_text into stack

file_undo

undo_parameter = true ;

size = GetWindowTextLength (hEdit); //Get size of the current document

char * redo_data = new char [size + 1 ];

// Get the content of the current document

GetWindowTextA (hEdit,redo_data,size + 1 );

redo_data[size] = ' \0 ' ;

string a(redo_data);

// Everytime we undo, we neen to push the old_text to

file_redo so that we can re do what we've just undo

push ( & file_redo,a); // A function of ‘file_stack.h’

string data = pop ( & file_undo); // A function of ‘file_stack.h’

old_text = data;

int len = data length ();

char * mydata = new char [len + 1 ];

strcpy (mydata,data c_str ()); // this is how we conver 'string' into 'char', becasue SetWindowText don't use 'string' type

// we use dynamic memmories so we need to set last element '\ 0' to finish the string

mydata[len] = ' \0 ' ;

SetWindowTextA (hEdit,mydata); // display the undo content

delete[] mydata;

delete[] redo_data;

}

}

Trang 15

V Phân tích giải thuật

a) Phân tích tính đúng đắn của giải thuật

Cho tới hiện tại, giải thuật trên đã được nhóm em kiểm tra bằng nhiều loại ví dụ với nhiều kích thước văn bản khác nhau và kết quả đạt được như ý

Trong quá trình sử dụng nếu chương trình gặp phải vấn đề mới thì nhóm em sẽ tiếp tục nghiên cứu cách xử lý

b) Xác định độ phức tạp của giải thuật

Ngoài vòng lặp chính để chạy chương trình, nhóm em chỉ sử dụng một dạng vòng lặp duy nhất trong quá trình thực hiện thuật toán là ở trong hàm tìm chiều dài length(stack*) và hàm loại bỏ node đáy: leak(stack*S) của thư viện Stack(“file_stack.h”):

Hình 7.

Dễ thấy chỉ có một vòng lặp duy nhất ở các hàm trên, vì vậy nếu chiều dài của stack là n thì ta có độ phức tạp của giải thuật là : O(n)

VI Mô tả triển khai trên ngôn ngữ lập trình cụ thể.

Trang 16

Sau đây là những hình ảnh của chương trình sau khi hoàn thành cơ bản:

 Nhìn từ trên xuống là lần lượt tên của chương trình, thanh công cụ làm việc, và trang soạn thảo

 Nhóm em đặt tên chương trình là TDText (shortcut cho Thinh Do Text)

 Trên thanh công cụ hiện tại có 4 chức năng: File, Undo, Redo và Help

Hình 8: Màn hình chính

Trong File thì gồm có 3 chức năng: Save, Open File và Exit:

 Save: Lưu văn bản

 Open File: cửa sổ tìm File sẽ mở ra, người dùng sẽ chọn File.txt

 Exit: Ép chương trình thoát, chương trình sẽ dừng ngay cả khi văn bản chưa được lưu

Ngày đăng: 14/06/2024, 18:50

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w