題目
應用MFC應用程序實現學生信息管理系統
(1)、設計一個學生類Student,包括數據成員:姓名、學號、二門課程(面向對象程序設計、高等數學)的成績。
(2)、創建一個管理學生的類Management,包括實現學生的數據的增加、刪除、修改、按課程成績排序、保存學生數據到文件及加載文件中的數據等功能。
(3)、創建一個基於對話框的MFC應用程序,程序窗口的標題上有你姓名、學號和應用程序名稱。使用(1)和(2)中的類,實現對學生信息和成績的輸入和管理。
(4)、創建一個單文檔的MFC應用程序,讀取(3)中保存的文件中的學生成績,分別用直方圖和折線方式顯示所有學生某課程的成績分佈圖。
效果圖
主窗口
添加數據窗口
修改數據窗口
查找
導出數據
導入數據
數據分析折線圖
數據分析直方圖
學生信息管理系統核心代碼
文件名:Student Information Management SystemDlg.h
// Student Information Management SystemDlg.h: 頭文件
#pragma once
// CStudentInformationManagementSystemDlg 對話框
class CStudentInformationManagementSystemDlg : public CDialogEx
{
// 構造
public:
CStudentInformationManagementSystemDlg(CWnd* pParent = nullptr); // 標準構造函數
// 對話框數據
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_STUDENTINFORMATIONMANAGEMENTSYSTEM_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 實現
protected:
HICON m_hIcon;
// 生成的消息映射函數
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedAddButton();
afx_msg void OnBnClickedDeleteButton();
afx_msg void OnBnClickedChangeButton();
afx_msg void OnBnClickedDataButton();
afx_msg void OnBnClickedFileSaveButton();
afx_msg void OnBnClickedFileLoadButton();
afx_msg void OnBnClickedSearchButton();
afx_msg void OnBnClickedSortButton();
CListCtrl m_List;
// 排序選擇
CComboBox m_Combo;
friend class Management;
};
文件名:Student Information Management SystemDlg.cpp
// Student Information Management SystemDlg.cpp: 實現文件
#include "pch.h"
#include "framework.h"
#include "Student Information Management System.h"
#include "Student Information Management SystemDlg.h"
#include "afxdialogex.h"
#include "CAddStudentDlg.h"
#include "Student.h"
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CStudentInformationManagementSystemDlg 對話框
CStudentInformationManagementSystemDlg::CStudentInformationManagementSystemDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_STUDENTINFORMATIONMANAGEMENTSYSTEM_DIALOG, pParent)
{
//m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);//設置圖標
}
void CStudentInformationManagementSystemDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST, m_List);
DDX_Control(pDX, IDC_SORT_COMBO, m_Combo);
}
BEGIN_MESSAGE_MAP(CStudentInformationManagementSystemDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_ADD_BUTTON, &CStudentInformationManagementSystemDlg::OnBnClickedAddButton)
ON_BN_CLICKED(IDC_DELETE_BUTTON, &CStudentInformationManagementSystemDlg::OnBnClickedDeleteButton)
ON_BN_CLICKED(IDC_CHANGE_BUTTON, &CStudentInformationManagementSystemDlg::OnBnClickedChangeButton)
ON_BN_CLICKED(IDC_DATA_BUTTON, &CStudentInformationManagementSystemDlg::OnBnClickedDataButton)
ON_BN_CLICKED(IDC_FILE_SAVE_BUTTON, &CStudentInformationManagementSystemDlg::OnBnClickedFileSaveButton)
ON_BN_CLICKED(IDC_FILE_LOAD_BUTTON, &CStudentInformationManagementSystemDlg::OnBnClickedFileLoadButton)
ON_BN_CLICKED(IDC_SEARCH_BUTTON, &CStudentInformationManagementSystemDlg::OnBnClickedSearchButton)
ON_BN_CLICKED(IDC_SORT_BUTTON, &CStudentInformationManagementSystemDlg::OnBnClickedSortButton)
END_MESSAGE_MAP()
// CStudentInformationManagementSystemDlg 消息處理程序
BOOL CStudentInformationManagementSystemDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 設置此對話框的圖標。 當應用程序主窗口不是對話框時,框架將自動
// 執行此操作
SetIcon(m_hIcon, TRUE); // 設置大圖標
SetIcon(m_hIcon, FALSE); // 設置小圖標
// TODO: 在此添加額外的初始化代碼
//在窗口左上角設置自己的姓名和學號(課設要求)
CString str = "學生信息管理系統";
SetWindowText(str);
//設置數據顯示區
m_List.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);//整行選擇、網格線
m_List.InsertColumn(0, "姓名", LVCFMT_CENTER, 100);
m_List.InsertColumn(1, "性別", LVCFMT_CENTER, 100);
m_List.InsertColumn(2, "學號", LVCFMT_CENTER, 100);
m_List.InsertColumn(3, "高等數學", LVCFMT_CENTER, 100);
m_List.InsertColumn(4, "課程設計", LVCFMT_CENTER, 100);
m_List.InsertColumn(5, "總分", LVCFMT_CENTER, 100);
//排序函數
//讀取文件函數
theApp.m_Management.LoadFile(&m_List);
//設置排序選擇按鈕
m_Combo.AddString(_T("總分"));
m_Combo.AddString(_T("課設"));
m_Combo.AddString(_T("高數"));
m_Combo.AddString(_T("學號"));
m_Combo.SetCurSel(2);
return TRUE; // 除非將焦點設置到控件,否則返回 TRUE
}
// 如果向對話框添加最小化按鈕,則需要下面的代碼
// 來繪製該圖標。 對於使用文檔/視圖模型的 MFC 應用程序,
// 這將由框架自動完成。
void CStudentInformationManagementSystemDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用於繪製的設備上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使圖標在工作區矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 繪製圖標
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//當用戶拖動最小化窗口時系統調用此函數取得光標
//顯示。
HCURSOR CStudentInformationManagementSystemDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
//添加數據按鈕
void CStudentInformationManagementSystemDlg::OnBnClickedAddButton()
{
// TODO: 在此添加控件通知處理程序代碼
theApp.m_Management.AddStudent(&m_List);
}
//刪除數據按鈕
void CStudentInformationManagementSystemDlg::OnBnClickedDeleteButton()
{
theApp.m_Management.DeleteStudent(&m_List);
}
//修改數據按鈕
void CStudentInformationManagementSystemDlg::OnBnClickedChangeButton()
{
// TODO: 在此添加控件通知處理程序代碼
POSITION pos = m_List.GetFirstSelectedItemPosition();//找到當前選中行
if (pos == NULL)
{
MessageBox(_T("請選擇要修改的數據!"), _T("警告"), MB_OK | MB_ICONWARNING);
return;
}
else
{
//將當前選中行數據寫入臨時變量
Student temp;
int nItem = m_List.GetNextSelectedItem(pos);
char tempgender[20];
m_List.GetItemText(nItem, 0, temp.name, sizeof(temp.name));
m_List.GetItemText(nItem, 1, tempgender, sizeof(tempgender));
m_List.GetItemText(nItem, 2, temp.ID, sizeof(temp.ID));
m_List.GetItemText(nItem, 3, temp.math, sizeof(temp.math));
m_List.GetItemText(nItem, 4, temp.program, sizeof(temp.program));
if (strcmp(tempgender,"女"))
{
temp.gender = true;
}
else
{
temp.gender = false;
}
//將臨時變量寫入全局變量m_student方便CAddStudentDlg調用
theApp.m_student=temp;
theApp.Tell = true;//CAddStudentDlg區分添加信息還是修改信息的關鍵
theApp.m_Management.ChangeStudent(&m_List);//
theApp.Tell = false;//還原默認值(默認爲添加數據)
}
}
//數據分析按鈕
void CStudentInformationManagementSystemDlg::OnBnClickedDataButton()
{
// TODO: 在此添加控件通知處理程序代碼
ShellExecute(NULL, "open", "C:\\Users\\17810\\source\\repos\\課程設計—學生信息管理系統\\DrawData\\Debug\\DrawData.exe", NULL, NULL, SW_SHOWNORMAL);
}
//導出數據按鈕
void CStudentInformationManagementSystemDlg::OnBnClickedFileSaveButton()
{
theApp.m_Management.SaveToFile(&m_List);
}
//導入數據按鈕
void CStudentInformationManagementSystemDlg::OnBnClickedFileLoadButton()
{
theApp.m_Management.GetFromFile(&m_List);
}
//查找按鈕
void CStudentInformationManagementSystemDlg::OnBnClickedSearchButton()
{
// TODO: 在此添加控件通知處理程序代碼
//將編輯框內容寫入臨時變量str
char str[20];
GetDlgItemText(IDC_SEARCH_EDIT, str, sizeof(str)); //獲取編輯框的信息
if ((CString)str == "")
{
MessageBox(_T("請輸入姓名或學號"), _T("警告"), MB_OK | MB_ICONWARNING);
return;
}
//查找函數
int nCount = m_List.GetItemCount();//listCtrl中的總行數
int i = 0, j = -1; // j是返回值,返回查找到的數據的行號
if (IDC_ID_RADIO== GetCheckedRadioButton(IDC_ID_RADIO, IDC_NAME_RADIO))//如果輸入的是學號
{
while (i < nCount)
{
if (m_List.GetItemText(i, 2) == (CString)str)
{
j = i;
break;
}
i++;
}
}
else
{
while (i < nCount)
{
if (m_List.GetItemText(i, 0) == (CString)str)
{
j = i;
break;
}
i++;
}
}
if (j!=-1)
{
//高亮顯示選中行
m_List.SetFocus();
m_List.SetItemState(j, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
m_List.EnsureVisible(j, FALSE);
}
else
{
MessageBox(_T("沒有找到該學生,請檢查輸入!"), _T("警告"), MB_OK | MB_ICONWARNING);
}
}
//排序按鈕
void CStudentInformationManagementSystemDlg::OnBnClickedSortButton()
{
// TODO: 在此添加控件通知處理程序代碼
int nSel = m_Combo.GetCurSel();//取得當前選中項
theApp.m_Management.SortStudents(&m_List,nSel);//排序函數
}
文件名:Student.h
#pragma once
class Student
{
public:
Student();
~Student();
char name[20];
char ID[20];
bool gender;
char math[5];
char program[5];
char sum[5];
void Sum();
friend class Management;
};
文件名:Student.cpp
#include "pch.h"
#include "Student.h"
Student::Student()
{
}
Student ::~Student()
{
}
void Student::Sum()
{
int Math = atoi(math);//類型轉換
int Program = atoi(program);
int all = Math + Program;
_itoa_s(all, sum, 10);//寫入類中
}
文件名:Mangement.h
#pragma once
#include <afxdialogex.h>
#include <afxdialogex.h>
#include "Student Information Management SystemDlg.h"
#include <iostream>
#include "CAddStudentDlg.h"
#include "Student.h"
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
class Management :
public CDialogEx
{
public:
Management() {};
~Management() {};
void AddStudent(CListCtrl* pList);//添加數據按鈕
void DeleteStudent(CListCtrl* pList);//刪除數據按鈕
void ChangeStudent(CListCtrl* pList);//修改數據按鈕
void SortStudents(CListCtrl* pList,int nSel);//排序按鈕,nSel是引入的行數
void LoadFile(CListCtrl* pList);//加載數據
void SaveToFile(CListCtrl* pList);//保存爲TXT文件
void GetFromFile(CListCtrl* pList);//從TXT文件導入
};
文件名:Management.cpp
#include "pch.h"
#include "Management.h"
bool sort_id(Student a, Student b) //學號大小比較函數
{
return _ttoi((CString)a.ID) < _ttoi((CString)b.ID); //將char轉換成CString,再轉化成int
}
bool sort_math(Student a, Student b)
{
return _ttoi((CString)a.math) > _ttoi((CString)b.math); //高數比較成績函數
}
bool sort_sum(Student a, Student b)
{
return (_ttoi((CString)a.program) + _ttoi((CString)a.math)) > (_ttoi((CString)b.program) + _ttoi((CString)b.math)); //總成績比較函數
}
bool sort_program(Student a, Student b)
{
return _ttoi((CString)a.program) > _ttoi((CString)b.program); //大小比較函數
}
//添加數據
void Management::AddStudent(CListCtrl* pList)
{
CAddStudentDlg temp;
temp.DoModal();//調用CAddStudentDlg將新信息寫入ListCtrl
LoadFile(pList);////更新ListCtrl界面
}
//刪除數據
void Management::DeleteStudent(CListCtrl* pList)
{
POSITION pos = pList->GetFirstSelectedItemPosition();//找到當前選中行
if (pos == NULL)
{
MessageBox(_T("請選擇要刪除的數據"), _T("警告"), MB_OK | MB_ICONWARNING);
return;
}
else
{
while (pos)
{
Student temp;
int nItem = pList->GetNextSelectedItem(pos);//獲取當前選中行的行號
pList->GetItemText(nItem, 2, temp.ID, sizeof(temp.ID));//將選中行的學號信息寫入臨時變量
pList->DeleteItem(nItem);//在ListCtrl中刪除選中行
CFile file;
if (!file.Open("./studentfile.dat", CFile::modeRead | CFile::shareDenyNone))
{
MessageBox(_T("無法打開文件!"), _T("錯誤"), MB_OK | MB_ICONERROR);
return;
}
CFile temporaryfile;//臨時數據存儲文件,如果不存在則創建新的
if (!temporaryfile.Open("./tempfile.dat", CFile::modeCreate | CFile::modeWrite | CFile::shareDenyNone))
{
MessageBox(_T("無法打開文件!"), _T("錯誤"), MB_OK | MB_ICONERROR);
return;
}
//讀取學生成績儲存文件,將未刪除的學生信息寫入臨時文件temporaryfile中
Student u;
while (file.Read(&u, sizeof(u)) == sizeof(u))
{
if ((CString)u.ID == (CString)temp.ID)//根據學號判斷是否該寫入
continue;
temporaryfile.Write(&u, sizeof(u));
}
file.Close();
temporaryfile.Close();
//這裏無論文件是否存在都創建了新的空文件studentfile.dat,是因爲原文件中有數據,需要清除
if (!file.Open("./studentfile.dat", CFile::modeCreate | CFile::modeWrite | CFile::shareDenyNone))
{
MessageBox(_T("無法打開文件!"), _T("錯誤"), MB_OK | MB_ICONERROR);
return;
}
if (!temporaryfile.Open("./tempfile.dat", CFile::modeRead | CFile::shareDenyNone))
{
MessageBox(_T("無法打開文件!"), _T("錯誤"), MB_OK | MB_ICONERROR);
return;
}
//讀取學生成績儲存文件,將臨時文件tempfile.dat中學生信息寫入真正存儲學生信息的studentfile.dat中
while (temporaryfile.Read(&u, sizeof(u)) == sizeof(u))
file.Write(&u, sizeof(u));
LoadFile(pList); //更新學生成績管理系統界面的信息
return;
}
}
}
//修改數據
void Management::ChangeStudent(CListCtrl* pList)
{
CAddStudentDlg tempdlg;
tempdlg.DoModal();
LoadFile(pList);
}
//排序
void Management::SortStudents(CListCtrl* pList, int nSel)
{
Student SomeStudent[100];
CFile file;
if (!file.Open("./studentfile.dat", CFile::modeRead | CFile::shareDenyNone))
{
MessageBox(_T("無法打開文件!"), _T("錯誤"), MB_OK | MB_ICONERROR);
return;
}
int i = 0;
while (file.Read(&SomeStudent[i], sizeof(SomeStudent[i])) == sizeof(SomeStudent[i]))
{
i++;
}
file.Close();
int b = (CString)SomeStudent[0].ID < (CString)SomeStudent[1].ID;
if (nSel == 0) //0是高數成績排序
std::sort(SomeStudent, SomeStudent + i, sort_math);
if (nSel == 1) //1是課設成績排序
std::sort(SomeStudent, SomeStudent + i, sort_program);
if (nSel == 2) //2是學號排序
std::sort(SomeStudent, SomeStudent + i, sort_id);
if (nSel == 3) //3是總成績排序
std::sort(SomeStudent, SomeStudent + i, sort_sum);
if (!file.Open("./studentfile.dat", CFile::modeWrite | CFile::shareDenyNone))
{
MessageBox(_T("無法打開文件!"), _T("錯誤"), MB_OK | MB_ICONERROR);
return;
}
int t = 0;
while (t < i) //將排好序的信息寫入studentfile.dat
{
file.Write(&SomeStudent[t], sizeof(SomeStudent[t]));
t++;
}
file.Close();
LoadFile(pList); ////更新ListCtrl界面
}
//更新ListCtrl界面
void Management::LoadFile(CListCtrl* pList)
{
CFile file;//打開數據存儲文件,如果不存在則創建新文件
if (!file.Open("./studentfile.dat", CFile::modeRead | CFile::modeCreate | CFile::modeNoTruncate | CFile::shareDenyNone))
{
MessageBox(_T("無法打開文件"), _T("錯誤"), MB_OK | MB_ICONERROR);
return;
}
pList->DeleteAllItems();//清屏
//重新寫入ListCtrl
Student u;
int i = 0;
while (file.Read(&u, sizeof(u)) == sizeof(u))
{
u.Sum();
pList->InsertItem(i, u.name);
if (u.gender)
pList->SetItemText(i, 1, _T("男"));
else
pList->SetItemText(i, 1, _T("女"));
pList->SetItemText(i, 2, u.ID);
pList->SetItemText(i, 3, u.math);
pList->SetItemText(i, 4, u.program);
pList->SetItemText(i, 5, u.sum);
i++;
}
file.Close();
}
//導出數據
void Management::SaveToFile(CListCtrl* pList)
{
if (pList->GetItemCount() <= 0)
{
MessageBox(_T("沒有需要保存的數據"), _T("警告"), MB_OK | MB_ICONWARNING);
return;
}
//調用系統另存爲窗口
char szFilters[] = _T("txt文件(*.txt)|*.txt|所有文件(*.*)|*.*||");
CFileDialog dlg(FALSE, _T("txt"), _T("學生信息"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilters, this);
if (dlg.DoModal() != IDOK)
return;
//獲取文件路徑
CString strFilePath;
strFilePath = dlg.GetPathName();
//判斷文件是否已存在,存在則刪除重建
DWORD dwre = GetFileAttributes(strFilePath);
if (dwre != (DWORD)-1)
{
DeleteFile(strFilePath);
}
//保存文件數據
FILE* fp;
fopen_s(&fp, strFilePath, "w");
//char str[1024];
if (fp == NULL)
{
printf("Save file ERROR\n");
return;
}
//獲取ListCtrl中每一列的第一行,即數據的類別
int nHeadNum = pList->GetHeaderCtrl()->GetItemCount();
LVCOLUMN lvcol;
char str_out[256];
int nColNum;
nColNum = 0;
lvcol.mask = LVCF_TEXT;
lvcol.pszText = str_out;
lvcol.cchTextMax = 256;
while (pList->GetColumn(nColNum, &lvcol))
{
nColNum++;
fprintf_s(fp, "%-30s", lvcol.pszText);
}
fprintf_s(fp, "\n", lvcol.pszText);//寫入文件中
//讀取行的數據
int nRow = pList->GetItemCount();
for (int i = 0; i < nRow; i++)
{
for (int j = 0; j < nColNum; j++)
{
CString str_data = pList->GetItemText(i, j);//獲取指定列,存爲字符串形式
fprintf_s(fp, "%-30s", str_data);
}
fprintf_s(fp, "\n");
}
fclose(fp);
MessageBox(_T("數據保存成功"), _T("成功"), MB_OK | MB_ICONASTERISK);
}
//導入數據
void Management::GetFromFile(CListCtrl* pList)
{
// TODO: 在此添加控件通知處理程序代碼
//調用系統窗口
char szFilters[] = _T("txt文件(*.txt)|*.txt|所有文件(*.*)|*.*||");
CFileDialog dlg(TRUE, _T("txt"), _T("學生信息"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilters, this);
dlg.m_ofn.lpstrTitle = _T("導入數據");
if (dlg.DoModal() != IDOK)
return;
//獲取文件路徑
CString strFilePath;
strFilePath = dlg.GetPathName();
//判斷文件是否存在
DWORD dwre = GetFileAttributes(strFilePath);
if (dwre != (DWORD)-1)//如果路徑正確
{
//清除之前所有數據
pList->DeleteAllItems();
int nColumnCount = pList->GetHeaderCtrl()->GetItemCount();
for (int i = 0; i < nColumnCount; i++)
{
pList->DeleteColumn(0);
}
}
else
{
MessageBox(_T("文件不存在!"), _T("警告"), MB_OK | MB_ICONWARNING);
return;
}
//讀取文件中的數據
FILE* fp;
fopen_s(&fp, strFilePath, "r");
char str[1024];
if (fp == NULL)
{
printf("Open file ERROR\n");
return;
}
int iRow = 0;
CFile file;
if (!file.Open("./studentfile.dat", /*CFile::modeCreate | */CFile::modeRead|CFile::modeWrite | CFile::shareDenyNone))
{
MessageBox(_T("無法打開文件!"), _T("錯誤"), MB_OK | MB_ICONERROR);
return;
}
Student u;
int nLength = 0;
while (fgets(str, sizeof(str), fp))
{
char _index[256] = "temp";
sprintf_s(_index, "%d", iRow);
pList->InsertItem(iRow, _index);
std::string s = str;
std::string buf;
std::stringstream ss(s);
std::vector<std::string> tokens;
int i = 0;
int j = 0;
while (ss >> buf)
{
if (buf.size() > 0)
{
tokens.push_back(buf);
if (iRow == 0)
{
pList->InsertColumn(++j, _T(tokens.at(i).c_str()), LVCFMT_CENTER, 100);
}
else
{
pList->SetItemText(iRow, i, tokens.at(i).c_str());
char temp[20];//臨時儲存性別,便於判斷
strcpy_s(temp, tokens.at(i).c_str());
switch (i)
{
case 0:
strcpy_s(u.name, tokens.at(i).c_str());
break;
case 1:
if (strcmp("女", temp))
{
u.gender = true;
break;
}
else
{
u.gender = false;
break;
}
case 2:
strcpy_s(u.ID, tokens.at(i).c_str());
break;
case 3:
strcpy_s(u.math, tokens.at(i).c_str());
break;
case 4:
strcpy_s(u.program, tokens.at(i).c_str());
break;
case 5:
strcpy_s(u.sum, tokens.at(i).c_str());
break;
default:
break;
}
}
i++;
}
}
iRow++;
if (iRow > 1)
file.Write(&u, sizeof(u));
}
fclose(fp);
pList->DeleteItem(0);
file.Close();
LoadFile(pList);//更新ListCtrl界面
}
繪製條形圖和折線圖代碼
請下載完整項目查看。