Repository: profthecopyright/Thunder_Class
Branch: master
Commit: 2327149a6a31
Files: 61
Total size: 125.3 KB
Directory structure:
gitextract_egk3lt1u/
├── .gitattributes
├── LICENSE
├── README.md
├── bin/
│ └── readme.md
├── doc/
│ ├── readme.md
│ ├── 废话说在前面.md
│ ├── 第一轮迭代正式计划.md
│ ├── 类图plantUML.txt
│ └── 类文档.md
├── format/
│ ├── .clang-format
│ ├── Cpp编码规范.md
│ ├── Readme.md
│ ├── format文件说明.md
│ └── testcase/
│ ├── 2.1.1.cpp
│ ├── 2.1.10.cpp
│ ├── 2.1.2.cpp
│ ├── 2.1.3.cpp
│ ├── 2.1.4.cpp
│ ├── 2.1.5.cpp
│ ├── 2.1.6.cpp
│ ├── 2.1.7.cpp
│ └── 2.2.7.cpp
├── req/
│ ├── 2020C++大作业“雷课堂”V2.md
│ └── readme.md
├── src/
│ ├── Qt/
│ │ ├── adminwindow.cpp
│ │ ├── adminwindow.h
│ │ ├── adminwindow.ui
│ │ ├── classroomwindow.cpp
│ │ ├── classroomwindow.h
│ │ ├── classroomwindow.ui
│ │ ├── dialogadduser.cpp
│ │ ├── dialogadduser.h
│ │ ├── dialogadduser.ui
│ │ ├── loginwindow.cpp
│ │ ├── loginwindow.h
│ │ ├── loginwindow.ui
│ │ ├── readme.md
│ │ ├── setipwindow.cpp
│ │ ├── setipwindow.h
│ │ ├── setipwindow.ui
│ │ ├── teachwindow.cpp
│ │ ├── teachwindow.h
│ │ └── teachwindow.ui
│ ├── basic/
│ │ ├── lib/
│ │ │ └── readme.md
│ │ └── readme.md
│ ├── core/
│ │ ├── readme.md
│ │ ├── taskcontroller.cpp
│ │ └── taskcontroller.h
│ ├── gui/
│ │ ├── guiadaptor.cpp
│ │ ├── guiadaptor.h
│ │ ├── qtguiadaptor.cpp
│ │ ├── qtguiadaptor.h
│ │ └── readme.md
│ ├── prototype/
│ │ └── readme.md
│ └── readme.md
└── trash/
├── UML_Demo.txt
├── readme.md
├── 初步流程计划.md
├── 类图plantUML.txt
├── 设计图草稿(求UML).pptx
└── 设计思路.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
================================================
FILE: README.md
================================================
# Thunder_Class
不就是个大作业嘛多大点事
[废话说在前面](doc/废话说在前面.md)
<br/><br/>
[2020C++大作业“雷课堂”V2作业要求](req/2020C++大作业“雷课堂”V2.md)
<br/><br/>
[类图(进行中)](doc/类图plantUML.png)
<br/><br/>
[类文档](doc/类文档.md)
<br/><br/>
[第一轮迭代正式计划](doc/第一轮迭代正式计划.md)
<br/><br/>
[代码风格规范及自动格式化](format)
================================================
FILE: bin/readme.md
================================================
## 可执行文件目录
================================================
FILE: doc/readme.md
================================================
## 文档/类图/设计流程
================================================
FILE: doc/废话说在前面.md
================================================
## 1. 关于目的
创建这个repo的初衷可能是帮大家一把,或者证明这个东西没那么难写,或者只是写着玩(类似的蛋疼事情我干过不少,比如用C++从零开始写人工神经网络)etc. 我只负责创建这个repo和这个文档,然后可能不定期出于无聊更新一下代码,大概率会更新但是不保证会更新,更不保证不会中途放弃。无论这个项目以后如何发展,希望不要扯到无意义的争论/撕逼中。理念上的话,作为一个作业,能简单就简单,实现功能是首要目的,所以不要吐槽为什么对需求定义这么低,为什么方法这么土,为什么连RSA加密都没有。先能用再说,以后要加什么花,那大家有兴趣就自便呗。
## 2. 开发思路
鉴于团队人数未知,进展计划未知(也许从头到尾只有我一个人自high,然后一群伸手党坐等,如果这样的话,相信我肯定会半途而废的),这个东西的开发模式可能会偏离标准的软件工程方法,而用一种比较接近直觉的、新手友好的方式,这样任何人想中途加入的话应该也会比较快入手。初步计划把相关模块拆分出来以后,每个模块分别各写各的,分别放在不同的目录里,可以各自作为一个独立的程序分别调试,然后把最恶心的东西放到最后(图形用户界面和业务流程类整合)。整合的时候肯定还要改一堆东西,但我认了。
然而这个事情并不等于完全没有设计。必要的类图/用例图该画还得画,规则该遵守还得遵守,不然搞出来就是一坨逻辑不清、到处依赖的翔,扯都扯不开。进度嘛随缘,如果有的话就在这个目录里。
## 3. 简要分析
这个东西真的没那么难做,要相信这只是个大作业,没让你把这个程序拿上App Store创收,或者承担全校师生的教学任务(利益相关:我连那老师是谁都不认识,也不会为课程团队说话,但也不要希望我为一些天天想搞大新闻的同学说话。搞这个完全是为了好玩,如果客观上顺便对某些同学起到了帮助作用那很荣幸,但要是有人抄代码被发现了锅也不是我的,不信的话请读一下GNU License的条款。代码就是代码,请不要牵涉道德/立场,我最讨厌这种无聊玩意)。所以很多网络应用要考虑的东西都不需要考虑(比如安全性、服务器荷载容量、各种异常情况等),说白了就是个玩具程序,即使最后写出一万行来,也不会有多复杂。或者说,这个东西按部就班做,是可以一点点做出来的(毕竟还有6周),没让你证明黎曼猜想,也没让你开发一个前所未有的船新算法出来不是吗?只不过这个分数没那么容易拿到而已嘛。我的理解就是,在T大混,不逼自己一把根本不知道自己有多牛逼不是吗?
好了进入正题,这玩意在我看来最奇葩的一点在于这个业务逻辑。照这个说法所有的用户(管理员/教师/学生)是在共用完全相同的程序。那谁是老大呢,应该是拿着管理员权限那个用户作为单中心验证机制对不对(不然怎么验证登录啊),然后教师和学生都只是普通用户。那么这事就有趣了,谁有那个数据库文件谁就是老大,然后Client和Server端完全不区分,服了。不过甲方说这样那就这样吧,细节问题,可能是为了照顾大家感受不用开发两个不同的程序吧(由此可以看出难度还是降低了不少的)。
然后就是这个模块设计了,要求文档上面哩哩啦啦列了12个功能,纯粹是吓唬人的,说白了就那么几个事:建立通讯,传输数据,记录状态日志。通讯的话要求用Socket那就Socket吧,语音和屏幕可以一起压成视频流推出去(如果采用单中心的话,对那个中心服务器还是有一定的带宽要求的,不过压制好了也许不会太离谱),然后答题、登录、签到、注意力这些东西都可以作为附加消息传输(我们也不用去管这个事如何防止学生开挂/作弊/假装听课其实在玩游戏etc),只要分清楚每个事要在学生端实现还是教师端实现还是服务器端实现就行了。然后底层操作的话,获取窗口/音源什么的就调用一下Windows/Mac的API,毕竟我们有CSDN和stackoverflow,这些都不是事。
总之这个程序设计费事的东西应该只有三大块,1建立网络传输逻辑/数据格式和相应的程序解释功能(比如一个单选题如何发送/修改/显示),2 通过OS的API真正实现它,3 搞出GUI把功能咪在一起。比较麻烦,但真的可行。
## 4. 如何参与项目
欢迎所有人,commit就好了。任何形式的贡献都可以,不一定非要代码。比代码更重要的其实是思路。任何参考资料/资源链接之类的都可以。有兴趣有热情且提交质量高的同学我会加到contributor里。毕竟开源的东西要靠社区,越多人贡献就越容易完成,行胜于言不是吗?
## 5. 开发环境
我的机子是Windows的,IDE用的VS 2012(别问为啥这么老,我懒得更新)。Mac的我管不着,但是希望有人能搞出相应的branch来。
================================================
FILE: doc/第一轮迭代正式计划.md
================================================
## 1. 需求
音频视频功能简化为传输图片功能,GUI端计时器(注意力功能)暂不实现,其余需求原则上应当实现。
## 2. 流程(同一标号下可并行)
1.
- 完善basic中的Data、Message、Status和InternalEvent等最基本数据类型/消息机制的定义(可不完全,随时添加,但每类都要有典型代表)。
- 设计制作GUI界面。
2.
- 完成basic.lib中的OSAPIWrapper类的操作系统时间和TCP端口传输功能(VideoEncoder可实现jpeg压缩算法),并封装入API类。
- 完成TaskController和GUIAdaptor之间的接口抽象逻辑定义。
3.
- 实现TaskExecutor的分析消息并调用各下属Agent处理的方法。
4.
- 完成LoginAgent和ServerLogAgent的功能。
- 完成ConnectionAgent和DataAgent的功能。
================================================
FILE: doc/类图plantUML.txt
================================================
@startuml
skinparam classAttributeIconSize 0
scale max 50000 height
scale max 50000 width
package basic
{
class Status
class InternalEvent
class Message
class Data
package basic.lib
{
class OSAPIWrapper
class AudioEncoder
class VideoEncoder
class API
}
}
package core
{
class TaskController
class TaskExecutor
class LoginAgent
class ConnectionAgent
class ServerLogAgent
class DataAgent
}
package gui
{
class GUIAdaptor
class QtGUIAdaptor
}
package Qt
{
class QtGUIWindow
class QTimer
}
abstract class TaskController
{
}
'note top of TaskController: Abstract class, as a delegate of Server or Client TaskController in the program
class InternalEvent
{
+ __event eventForGUI(Message):void
+ __event eventForCore(Message):void
}
'note bottom of InternalEvent: Event generated by TaskController object to change GUI and handled by GUIAdaptor
class Data
{
- dataType
}
class DataAgent
{
+ serialize(Data):string
+ deserialize(string):Data
}
class ConnectionAgent
{
}
class LoginAgent
{
}
class ServerLogAgent
{
}
class Status
{
-connectionList: vector<string>
}
abstract class GUIAdaptor
{
-TaskController:TaskController
}
class QtGUIAdaptor
{
-window:QtGUIWindow
}
GUIAdaptor <|.. QtGUIAdaptor
TaskController <|.. TaskExecutor
TaskController ..> InternalEvent
TaskExecutor ..> LoginAgent
TaskExecutor ..> ConnectionAgent
TaskExecutor ..> ServerLogAgent
TaskExecutor ..> DataAgent
TaskExecutor ..> Status
QtGUIAdaptor ..> QtGUIWindow
QtGUIAdaptor ..> QTimer
GUIAdaptor ..> InternalEvent
GUIAdaptor ..> TaskController
Message ..> Data
InternalEvent ..> Message
ConnectionAgent ..>InternalEvent
API ..> OSAPIWrapper
API ..> AudioEncoder
API ..> VideoEncoder
@enduml
================================================
FILE: doc/类文档.md
================================================
## basic包:底层API、算法、各种通信数据结构定义
Data:核心类。定义单个程序内部不同模块之间的数据传输格式(基于原始类型,如未压缩的bitmap图像点阵等)
Message:核心类。定义单个程序内部不同模块之间的消息传输格式,包括数据消息与控制消息两种。数据消息如音频、视频、单选题等数据体量大的消息,其中包装了Data对象。控制消息包括点名、登录登出等。不同类型的消息由宏定义对应的消息码。
InternalEvent:核心类。定义两个方法:eventforGUI()为从核心逻辑TaskController传递给GUIAdaptor的、通常需要对图形用户界面作出响应/改变的控制事件,eventforCore()为从connectionAgent传递给TaskController的事件,一般发生在接收到端口传来的数据时由connectionAgent触发。
Status:核心类。记录程序的运行状态的数据结构(如是server mode还是client mode,当前所有连接的list,日志文件流对象等等)。
+ basic.lib子包:独立API与各种(第三方)基本算法封装
API:静态类,核心类。所有方法均为静态方法,可直接从外部调用。
OSAPIWrapper:特殊核心类,将操作系统API(包括Socket通信,音频及窗口捕获、麦克风控制、文件读写、获取系统时间等)与上层隔离。可能派生Mac和Win版本的子类。
VideoEncoder:核心类。图像/视频压缩算法。如JPEG用离散余弦变换(DCT)。也可考虑FFmpeg。
AudioEncoder:核心类。音频压缩算法。
## core包:业务流程控制及业务逻辑执行
TaskController: 抽象类,核心类,业务逻辑类。定义了对用户在GUI上的操作事件类型(抽象意义上)的响应机制。
TaskExecutor:核心类,实际业务逻辑类。TaskController的实现,具体响应用户操作,并(可能)指派各下级Executor类具体执行。Client Mode的功能主要包括发送登录、注意力、答题、语音消息,接收单选题、音视频、点名消息。
Server Mode的功能主要包括接收登录、注意力、答题、语音消息,发送单选题、音视频、点名消息,维护学生账户数据库(本地csv)、记录服务器日志(本地txt)等。
LoginAgent:负责登录验证相关功能(包括用户账户数据库信息维护)。
ConnectionAgent:负责处理端口连接,发送/接收(序列化后)的数据,可__raise一个InternalEvent交由上级TaskExecutor处理。
ServerLogAgent:负责服务器日志记录。原则上收到任何Message以后可以直接调用它向日志文件中写一个记录。
DataAgent:负责serialize/deserialize,即实现内部数据格式(Data对象)和端口可以直接发送的字符串(字节流)之间的转换(可能用到压缩/解压缩算法)。
## gui包:GUI相关
GUIAdaptor: 业务流程类,抽象类,负责上层GUI与下层核心业务逻辑之间的通信。依赖于TaskController(拥有其指针)国。GUI对核心的汇报通过调用TaskController定义的各接口方法完成;核心对GUI的汇报通过__raise关键字产生InnerEvent类型的事件实现,该事件将被GUIAdaptor相应,从而改变GUI。main函数直接创建GUIAdaptor对象,由其进一步引导程序启动流程,如创建GUI窗体和TaskController、引导登录等。
QtGUIAdaptor: GUIAdaptor的子类,一种基于Qt的GUI实现(同理还可基于MFC实现;基于Qt的实现也可有不同的界面样式等等)。
## Qt包:开发环境类
QtGUIWindow:GUI窗体、控件相关各类总称。
QTimer:Qt自带计时器,用于GUI层面的简单计时(如答题倒计时),不依赖于操作系统绝对时间。
================================================
FILE: format/.clang-format
================================================
---
# true: 关闭所有规则
DisableFormat: false
# C++ 语言
Language: Cpp
Standard: Cpp11
## 2. 编码规范正文 =================================
## 2.1 格式 ---------------------------------------
## 2.1.1* [建议] 空行的使用
# 要保留空行这里就不能设为 0
# unsigned: 允许保留的最大连续空行数
MaxEmptyLinesToKeep: 2
# 这个我不知道有啥必要,关了
# true 保留代码块内部开头的空行
KeepEmptyLinesAtTheStartOfBlocks: false
## 2.1.2 哪里应该使用空格
#> 二元操作符,在其两边各加一个空格
# true 赋值运算加空格
SpaceBeforeAssignmentOperators: true
#> 控制语句 if, for, while, switch 和之后的 ( 之间加一个空格
# ControlStatements 仅在控制流关键字的括号前加空格
SpaceBeforeParens: ControlStatements
# true: for 后面加空格
SpaceBeforeRangeBasedForLoopColon: true
# `//` 型注释前的空格数
SpacesBeforeTrailingComments: 1
## 2.1.3 哪里不应该使用空格
#> 不要在引用操作符前后使用空格。引用操作符指 . 和 ->,以及 []
# false 第一个 `[]` 前不加空格(之后的默认都不加)
SpaceBeforeSquareBrackets: false
# false `[]` 内部首尾不加空格
SpacesInSquareBrackets: false
#> 不要在一元操作符和其操作对象之间使用空格
# false `!` 后面不加空格
SpaceAfterLogicalNot: false
## 没说加的都不加吧
# false `template` 后面不加空格
SpaceAfterTemplateKeyword: false
# false constructor initializer 的 `:` 前不加空格
SpaceBeforeCtorInitializerColon: false
# false 类继承时 `:` 前不加空格
SpaceBeforeInheritanceColon: false
# 规范没有明说。空参数写个 `void` 吧
# false 函数的空参数列表内不加空格
SpaceInEmptyParentheses: false
# false `<>` 内部首尾不加空格
SpacesInAngles: false
# true: cpp11 风格的列表,`{}` 内部的首尾不加空格
Cpp11BracedListStyle: true
# false cpp11 风格的列表,`{}` 前不加空格
SpaceBeforeCpp11BracedList: false
# false 条件语句的 `()` 内部首位不加空格
SpacesInConditionalStatement: false
# false `()` 内部首位不加空格
SpacesInParentheses: false
# 都说了用 cpp 风格的 cast
# ref: 2.9.3 尽量使用 C++ 风格的类型转换
# false C 风格的强制类型转的 `()` 后不加空格
SpaceAfterCStyleCast: false
# false C 风格的强制类型转的 `()` 内部不加空格
SpacesInCStyleCastParentheses: false
## 2.1.4 缩进
#> 以4个空格为一个缩进单位
IndentWidth: 4
TabWidth: 4
UseTab: Never
## 2.1.5 长语句的书写格式
# true: 在操作符后换行,操作数对齐
AlignOperands: false
# 80 字符应换行
ColumnLimit: 80
# false 不依靠统计调整自动调整换行符
DeriveLineEnding: false
# false 不使用 CRLF。建议通过 git 管理换行符
# UseCRLF: false
# true 注释自动折行
ReflowComments: true
## 2.1.6 清晰划分控制语句的语句块
# 此处使用 `{` 和 `}` 均单独占一行的格式
# None: 函数的返回类型不换行
AlwaysBreakAfterReturnType: None
# 自定义的 `{` 换行
BreakBeforeBraces: Custom
# 这里采用默认全部换行
BraceWrapping:
AfterCaseLabel: true
AfterClass: false
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
# 换行但不缩进括号
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
# 在非 `=` 的操作符后换行
BreakBeforeBinaryOperators: NonAssignment
## 2.1.7 一行只写一条语句或标号
# false: 不允许短"case"合并到一行
AllowShortCaseLabelsOnASingleLine: false
# None: 不允许短"函数"合并到一行
AllowShortFunctionsOnASingleLine: None
# Never: 不允许短"if分支"合并到一行
AllowShortIfStatementsOnASingleLine: Never
# false: 不允许短"循环体"合并到一行
AllowShortLoopsOnASingleLine: false
## 2.1.9* [建议] 在表达式中使用括号
# 这个需要个人注意
## 2.1.10 将操作符 *(Dereferencing)、& 和类型写在一起
# Left: `*` 靠近类型
PointerAlignment: Left
# false: 不依靠统计调整 `*` 和 `&` 的位置
DerivePointerAlignment: false
## 2.2 注释 ---------------------------------------
# 大多数都需要手动添加。从略
## 2.2.4* [建议] 对每个空循环体要给出确认性注释
# Never: 不允许短"block"合并到一行。`}` 始终换行
AllowShortBlocksOnASingleLine: Never
## 2.2.5* [建议] 对多个 case 共用一个出口的情况给出确认性注释
# 缩进 case
IndentCaseLabels: true
## 2.2.7* [建议] 行末注释尽量对齐
# true: 行尾注释自动对齐
AlignTrailingComments: true
# true 自动为命名空间添加末尾的成对注释
FixNamespaceComments: true
## 2.3+ 自动格式化无法处理。略 ----------------------
## 其他默认选项 ====================================
# BasedOnStyle: Microsoft
# 通过设置 `-fallback-style=none` 可以跳过没设置的格式
# 想用某个选项就取消注释
# false 多行连续字符串在 `=` 后不换行
# AlwaysBreakBeforeMultilineStrings: false
# 三元表达式换行后置于行首
# BreakBeforeTernaryOperators: true
# Preserve: include 保留原状
IncludeBlocks: Preserve
# None 宏定义部分不处理缩进
IndentPPDirectives: None
# false 不对 using 排序
SortUsingDeclarations: false
# 默认的格式化惩罚值
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 1000
# 自带的结束符
...
================================================
FILE: format/Cpp编码规范.md
================================================
C++ 程序设计与训练课程编码规范
============================
## 1. 前言
本编码规范针对 C++ 语言。制定本规范的目的:
+ 适用于课下训练、大作业,督促学生养成良好的编码习惯
+ 提高代码的健壮性,使代码更安全、可靠
+ 提高代码的可读性,使代码易于查看和维护
本文档分别对 C++ 程序的格式、注释、标识符命名、语句使用、函数、类运用、程序组织、公共变量等方面做出了要求。
规范分为两个级别——规则和建议。
规则级的规范要求学生必须要遵守,建议级的规范学生应尽量遵守。
----
## 2. 编码规范正文
### 2.1 格式
#### 2.1.1 空行的使用
级别:建议
描述:
+ 在头文件和实现文件中,各主要部分之间要用空行隔开。
所谓文件的主要部分,包括:序言性注释、防止被重复包含部分(只在头文件中)、
`#include` 部分、`#define` 部分、类型声明和定义部分、实现部分等等。
+ 在一个函数中,完成不同功能的部分,要用空行隔开。
理由:段落分明,提高代码的可读性。
#### 2.1.2 哪里应该使用空格
级别:规则
描述:
1. 在使用赋值运算符、关系运算符、逻辑运算符、位运算符、算术运算符等二元操作符时,在其两边各加一个空格。
例:`nCount = 2;` 而不是 `nCount=2;`
2. 三目运算符的 `?` 和 `:` 前后均各加 1 个空格。
3. 函数的各参数间、数组初始化列表的各个初始值间,要用 `,` 和后续一个空格隔开。
例:`void GetDate(int x, int y);`
而不是 `void GetDate(int x,int y);` 或 `void GetDate(int x ,int y);`
4. 控制语句 `if, for, while, switch` 和之后的 `(` 之间加一个空格。
5. 控制语句 `if, for, while, switch` 之后的 `)` 与 `{` 之间加一个空格(同行的情况下)。
6. 控制语句 `do` 和之后 `{` 之间加一个空格(同行的情况下)。
7. `case` 的常数表达式之后、`default` 之后的 `:` 前面,要有一个空格。
理由:提高代码的可读性。
#### 2.1.3 哪里不应该使用空格
级别:规则
描述:
1. 不要在引用操作符前后使用空格。引用操作符指 `.` 和 `->`,以及 `[]`。
2. 不要在 `::` 前后使用空格。
3. 不要在一元操作符和其操作对象之间使用空格,一元操作符包括 `++`、`--`、`!`、`&`、`*` 等。
4. `;` 前不能有空格。
理由:提高代码的可读性。
举例:
```cpp
// 不要像下面这样写代码
m_pFont -> Font;
// 应该写成这样
m_pFont->Font;
```
#### 2.1.4 缩进
级别:规则
描述:对程序语句要按其逻辑进行水平缩进,以4个空格为一个缩进单位,使同一逻辑层次上的代码在列上对齐。
理由:提高代码的可读性。
#### 2.1.5 长语句的书写格式
级别:规则
描述:
较长的语句(长度大于80字符,包含缩进)要分成多行书写。
长表达式要在低优先级操作符处分新行,操作符放在新行之首,
划分出的新行要进行适当的缩进,缩进长度以4个空格为单位。
理由:提高代码的可读性。
举例:
```cpp
// 下面是一个处理的较为合理的例子
nCount = Fun1(nl, n2, n3)
+ (nNumberl * GetDate(n4, n5, n6)) * nNumber1;
```
#### 2.1.6 清晰划分控制语句的语句块
级别:规则
描述:
1. 控制语句 `if, for, while, do...while, switch` 的语句部分一定要用 `{` 和 `}` 括起来
(即使只有一条语句)。
2. `{` 与控制语句同行或者,`{` 和 `}` 单独占一行,与控制语句的首字母应处在同一列上。
3. `}` 单独占一行。但在 `do...while` 结构中,`while` 前的 `}` 不能单独占一行,必须和 `while` 同行。
理由:这样做,能够划分出清晰的语句块,使语句的归属明确,使代码更加容易阅读和修改。
举例:
```cpp
// 不要像下面这样写代码
if (x == 0)
return;
else
while (x > min)
x--;
// 应该这样写
if (x == 0)
{
return;
}
else
{
while (x > min)
{
x--;
}
}
```
#### 2.1.7 一行只写一条语句或标号
级别:规则
规则描述:一行只写一条程序语句或标号(仅针对 `case`)。
理由:提高代码的可读性。
举例:
```cpp
// 不要这样写
x = x0; y = y0;
while (IsOk(x)) {x++;}
// 应该这样写代码
x = x0;
y = y0;
while (IsOk(x))
{
x++;
}
```
#### 2.1.8 一次只声明、定义一个变量
级别:规则
描述:一次(一条声明、定义语句)只声明、定义一个变量。
理由:提高代码的可读性,方便加入后置注释。
举例:
```cpp
// 不要这样写
int width, length;
// 应该这样写
int width;
int length;
```
#### 2.1.9 在表达式中使用括号
级别:建议
描述:对于一个表达式,在一个二元、三元操作符操作的操作数的两边,应该放置 `(` 和 `)`,直到最高运算逻辑。
理由:避免出现不明确的运算、赋值顺序,提高代码的可读性。
举例:
```cpp
//下面这行代码
result = fact / 100 * number + rem;
//最好写成这样
result = ((fact / 100) * number) + rem;
```
#### 2.1.10 将操作符 `*`(Dereferencing)、`&` 和类型写在一起
级别:规则
描述:在定义指针变量时,将操作符和类型写在一起。
理由:统一格式,提高代码的可读性。
举例:
```cpp
// 不要像下面这样写代码
char *s;
// 而应该写成这样
char* s;
```
----
### 2.2 注释
这一部分对程序注释提出了要求。
程序中的注释是程序与日后的程序读者之间通信的重要手段。
良好的注释能够帮助读者理解程序,为后续阶段进行测试和维护提供明确的指导。
下面是关于注释的基本原则:
1. 注释内容要清晰明了,含义准确,防止出现二义性。
2. 边写代码边注释,修改代码的同时修改相应的注释,保证代码与注释的一致性。
#### 2.2.1 对函数进行注释
级别:规则
描述:
+ 在函数的声明之前,要给出精练的注释(不必牵扯太多的内部细节),让使用者能够快速获得足够的信息使用函数。
格式不做具体要求。
+ 在函数的定义之前,要给出足够的注释。注释格式要求如下:
```cpp
/***************************************************************
【函数名称】 (必需)
【函数功能】 (必需)
【参数】 (必需。标明各参数是输入参数还是输出参数。)
【返回值】 (必需。解释返回值的意义。)
【开发者及日期】 (必需)
【更改记录】 (若有修改,则必需注明)
****************************************************************/
```
理由:提高代码的可读性。
#### 2.2.2 对类进行注释
规范级别:规则
描述:在类的声明之前,要给出足够而精练的注释。注释格式要求如下:
```cpp
/***************************************************************
【类名】 (必需)
【功能】 (必需)
【接口说明】 (必需)
【开发者及日期】 (必需)
【更改记录】 (若修改过则必需注明)
****************************************************************/
```
理由:提高代码的可读性。
#### 2.2.3 对文件进行注释
级别:规则
描述:在头文件、实现文件的首部,一定要有文件注释,用来介绍文件内容。注释格式要求如下:
```cpp
/***************************************************************
【文件名】 (必需)
【功能模块和目的】 (必需)
【开发者及日期】 (必需)
【更改记录】 (若修改过则必需注明)
****************************************************************/
```
理由:提高代码的可读性。
#### 2.2.4 对每个空循环体要给出确认性注释
级别:建议
描述:建议对每个空循环体给出确认性注释。
理由:提示自己和别人,这是空循环体,并不是忘了。
举例:
```cpp
while (g_bOpen == 1)
{
// 空循环
}
```
#### 2.2.5 对多个 `case` 共用一个出口的情况给出确认性注释
级别:建议
描述:建议对多个 `case` 语句共用一个出口的情况给出确认性注释。
理由:提示自己和别人,这几个 `case` 语句确实是共用一个出口,并不是遗漏了。
举例:
```cpp
switch (nNumber)
{
case 1:
nCount++;
break;
case 2:
case 3:
nCount--;
break; // 当 nNumber 等于 2 或 3 时,进行同样的处理
default:
break;
}
```
#### 2.2.6 其它应该考虑进行注释的地方
级别:建议
描述:
除上面说到的,对于以下情况,也应该考虑进行注释:
+ 变量的声明、定义。通过注释,解释变量的意义、存取关系等;
例如:
```cpp
int m_iNumber; // 记录图形个数。被 `SetDate()`、`GetDate()` 使用。
```
+ 数据结构的声明。通过注释,解释数据结构的意义、用途等;
例如:
```cpp
// 定义结构体,存储元件的端点。用于将新旧的端点对应。
typedef struct
{
short int nBNN;
short int nENN;
short int nBNO;
short int nENO;
} Element;
```
+ 分支。通过注释,解释不同分支的意义;
例如:
```cpp
if (m_iShortRadio == 0) // 三相的情况
{
strvC.Format("%-10.6f", vC);
straC.Format("%-10.6f", aC);
}
else if (m_iShortRadio == 1) // 两相的情况
{
strvC = _T("");
straC = _T("");
}
```
+ 调用函数。通过注释,解释调用该函数所要完成的功能;
例如:
```cpp
SetDate(m_nNumber); // 设置当前的图形个数。
```
+ 赋值。通过注释,说明赋值的意义;
例如:
```cpp
m_bDraw = 1; // 将当前设置为绘图状态
```
+ 程序块的结束处。通过注释,标识程序块的结束。
例如:
```cpp
if (name == White)
{
...
if (age == 20)
...
} // 年龄判断、处理结束
...
} // 姓名判断、处理结束
```
+ 其它有必要加以注释的地方
理由:提高代码的可读性。
#### 2.2.7 行末注释尽量对齐
级别:建议
描述:同一个函数或模块中的行末注释应尽量对齐。
理由:提高代码的可读性。
举例:
```cpp
nCount = 0; // 计数器,表示正在处理第几个数据块
BOOL bNeedSave; // 是否保存从服务器返回的数据
DWORD BytesWritten; // 写入的数据长度
```
#### 2.2.8注释量
级别:规则
描述:注释行的数量不得少于程序行数量的 1/3。
----
### 2.3 命名
对标识符和文件的命名要求。
#### 2.3.1 标识符命名要求
级别:规则
描述:
在程序中声明、定义的变量、常量、宏、类型、函数,在对其命名时应该遵守统一的命名规范。
具体要求如下:
+ 变量。
变量名 = 作用域前缀 + 类型前缀 + 物理意义。
物理意义部分应当由至少一个英文描述单词组成,各英文描述单词的首字母分别大写,其他字母一律小写。
对于不同作用域的变量,其命名要求如表 2-1 所示;
对于不同数据类型变量,其命名要求如表 2-2 所示:
**表 2-1 作用域前缀**
| 变量种类 | 作用域前缀要求 | 示例 |
|:--------------|:---------------:|:------------------------------------:|
| 全局变量(注1) | g_ | g_iNumber <br/>全局整型变量 |
| 全局指针变量(注2)、<br/>文件作用域变量(注3) | g_p | g_pNumber |
| 对象级变量 | m_ | m_cClassCode <br/>文件作用域整型变量 |
| 对象级指针变量、<br/>文件作用域指针变量 | m_p | m_pNumber |
| 局部变量 | 无 | fPrice <br/>局部单精度浮点型变量 |
| 静态局部变量 | s_ | s_Number |
> 注释:
> 1. 在整个程序中可以使用
> 2. 类内数据成员
> 3. 文件中静态变量。只在某个 `.c` 文件中可以使用。
> 但如整个程序只有一个 `.c` 文件,应当认为是全局变量
**表2-2类型前缀**
| 数据类型 | 类型前缀 | 示例 |
|:-----------------:|:----------------:|:------------------------------------:|
| `char` | c (优先级第3) | m_cClassCode <br/>文件作用域整型变量 |
| `int` | i (优先级第3) | g_iNumber <br/>全局整型变量 |
| `short int` | n (优先级第3) | m_nCount <br/>文件作用域短整型变量 |
| `long int` | l (优先级第3) | lCount <br/>局部长整型变量 |
| `long long int` | ll (优先级第3) | llBigCount <br/>局部长长整型变量 |
| 用 `unsigned` 修饰 | u (优先级第2)(注1)| g_ulCount <br/>全局无符号长整型变量 |
| `float` | f (优先级第3) | fPrice <br/>局部浮点型变量 |
| `double` | r (优先级第3) | rPrice <br/>局部浮点型变量 |
| 指针 | p (优先级第1) | g_pulPrice <br/>全局指向无符号长整型的指针变量 |
> 注释:
> 1. 但当仅为 `unsigned int` 时,用 `u` 替换 `i`
+ 常量
常量的名字要全部大写,包括至少一个英文单词。
常量指:`const` 修饰的量。如 `const int NUMBER = 100;`
枚举量。如 `enum Number{ONE,TWO, THREE};`
+ 宏
所有用宏形式定义的名字,包括宏常量和宏函数,名字要全部大写。
+ 自定义类型类型
自定义类型名应以大写字母打头。
C++ 中自定义类型包括:
`class`、`struct`、`enum`、`union`、`typedef` 声明的类型、`namespace`。
例如:
+ `typedef struct Student;`
+ `class CMsgDia log;`
函数名应以大写字母打头,由动词性英文单词或动宾型英文短语构成。
例如:`void GetCount();`
+ 下面还有一些在命名时应该遵守的基本规范:
+ 名中含多于一个单词时,每个单词的第一个字母大写。
例如:`m_LastCount` 中要大写L和C;
+ 不要使用以下划线打头的标识符。
例如:`_bFind` 是不允许出现的变量;
+ 不要使用仅用大小写字母区分的名称。
例如:`m_Find` 和 `M_FIND`;
+ 尽量使用有意义的名字。应做到见其名知其意。
例如:`m_uErrorCode` 表示错误的代码;
理由:减少命名冲突;提高代码的可读性。
#### 2.3.2 标识符长度要求
级别:规则
描述:
在程序中声明、定义的变量、常量、宏、类型、函数,它们的名字长度要在4至25个字符之内
(下限不包括前缀,上限包括名字中所有的字符)。
对于某些已经被普遍认同 的简单命名,可不受本规则的限制。
如 for 循环的循环记数变量,可使用 `i`、`j`、`x`、`y` 等简单字符命名。
如名字过长,可使用缩写,缩写时应当尽可能保留影响发音的辅音字母.
例如: `Index` 可缩写为 `Idx`,`Button` 可缩写为 `Btn`,`Solution` 可缩写为 `Sln`。
理由:名字长度应该在一个恰当的范围内,名字太长不够简洁,名字太短又不能清晰表达含义。
#### 2.3.3 文件命名要求
级别:建议
描述:
代码文件的名字要与文件中声明、定义的重要重要函数名字或整体功能描述基本保持一致,
使功能与类文件名建立联系。
如 `math.h` 包括的都是和数学运算相关的函数声明。
举例:
将类 `CMsgDialog` 的头文件和实现文件命名为 `msgdialog.h` 和 `msgdialog.cpp`
就是一种比较简单、恰当的方法。
理由:使应用程序容易理解。
----
### 2.4 语句
对具体程序语句的使用要求。
#### 2.4.1 一条程序语句中只包含一个赋值操作符
级别:规则
描述:
在一条程序语句中,只应包含一个赋值操作符。赋值操作符包括:
`=, +=, -=, *=, /=, %=, >>=, <<=, &=, |=, !=, ^=, ++, --`
理由:避免产生不明确的赋值顺序。
举例:
```cpp
// 不要这样写
b = c = 5;
a = (b * c) + d++;
// 应该这样写
c = 5;
b = c;
a = (b * c) + d;
d++;
```
#### 2.4.2 不要在控制语句的表达式中使用赋值操作符
级别:建议
描述:
不要在控制语句 `if, while, for` 和 `switch` 的条件表达式中使用赋值操作符。
赋值操作符包括: `=, +=, -=, *=, /=, %=, >>=, <<=, &=, |=, !=, ^=, ++, --`
理由:
已个类似于 `if (x = y)` 这样的写法是不明确、不清晰的,
代码的作者也许是想写成这样:`if (x == y)`。
举例:
```cpp
//不要像下面这样写代码:
if (x -= dx)
{
...
}
//应该这样写:
x -= dx;
if (x)
{
...
}
```
#### 2.4.3 赋值表达式中的规定
级别:建议
描述:
在一个赋值表达式中:
+ 一个左值,在表达式中应该仅被赋值一次。
+ 对于多重赋值表达式,一个左值在表达式中仅应出现一次,不要重复出现。
理由:避免产生不明确的赋值顺序。
举例
```cpp
// 不要像下面这样写代码:
i = t[i++]; // 一个左值,在表达式中应该仅被赋值一次
a = b = c + a; // 对于多重赋值表达式,一个左值在表达式中仅应出现一次,不能重复出现。
i = t[i] = 15; // 对于多重赋值表达式,一个左值在表达式中仅应出现一次,不能重复出现。
```
#### 2.4.4 禁用 Goto 语句
级别:规则
描述:程序中不要使 `goto` 语句。
理由:
这条规则的目的是为了确保程序的结构化,因为滥goto语句会使程序流程无规则,可读性差。
Goto 语句只在一种情况下有使价值,就是当要从多重循环深处跳转到循环之外时,效率很高,
但对于一般要求的软件,没有必要费劲心思追求多么高的效率,
而且效率主要是取决于算法,而不在于个别的语句技巧。
#### 2.4.5 避免对浮点数值类型做精确比较
级别:规则
描述:不要对浮点类型的数据做等于、不等于这些精确的比较判断,要用范围比较代替精确比较。
理由:
由于存在舍入的问题,计算枧内部不能精确的表示所有的十进制浮点数,
用等于、不等于这种精确的比较方法就可能得出与预期相反的结果。
所以应该用大于、小于等范围比较的方法代替精确比较的方法。
举例
```cpp
// 不要像下面这样写代码:
float number;
...
if (number == 0) // 精确比较
```
#### 2.4.6 对 `switch` 语句中每个分支结尾的要求
级别:规则
描述:
`switch` 语句中的每一个 `case` 分支,都要以 `break` 作为分支的结尾
(几个连续的空 `case` 语句允许共一个)
理由:使代码更容易理解;减少代码发生错误的可能性。
#### 2.4.7 `switch` 语句中的 `default` 分支
级别:规则
描述:
在 `switch` 语句块中,一定要有 `default` 分支来处理其它情况。
仅在 `switch` 中所有 `case` 已经包含了被判定表达式全部取值范围时候,可以不受本规则限制。
理由:用来处理 `switch` 语句中默认、特殊的情况。
#### 2.4.8 对指针的初始化
级别:规则
描述:在定义指针变量的同时,对其进行初始化。如果定义时还不能为指针变量赋予有效值,则使其指向 `NULL`。
理由:减少使用未初始化指针变量的几率。
举例
```cpp
// 不要这样写代码
int* y;
y = &x;
// 应该这样写
int* y = &x;
```
#### 2.4.9 释放内存后的指针变量
级别:规则
描述:
当指针变量所指的内存被释放后,应该赋予指针一个合理的值。
除非该指针变量本身将要消失这种情况下不必赋值,否则应赋予 `NULL`。
理由:保证指针变量在其生命周期的全过程都指向一个合理的值。
#### 2.4.10 使用正规格式的布尔表达式
规范级别:建议
规则描述:对于 `if, while, for` 等控制语句的条件表达式,建议使用正规的布尔格式。
理由:使代码更容易理解。
举例
```cpp
//不要像下面这样写代码:
whiIe (1)
{
...
}
if (test)
{
...
}
for (i = 1; function_call(i); i++)
{
...
}
// 最好这样写:
AlwaysTrue = true;
while (AlwaysTrue == true)
{
...
}
if (test == true)
{
...
}
for (i = 1; function_call(i) == true; i++)
{
...
}
```
#### 2.4.11 `new` 和 `delete`
规范级别:规则
规则描述:
局部的 `new` 和 `delete` 要成对出现;
`new` 要与 `delete` 对应,`new[]` 要与 `delete[]` 对应。
理由:防止内存泄露。
----
### 2.5 函数
对函数的要求。
#### 2.5.1 明确函数功能
级别:规则
描述:函数体代码长度不得超过 100 行(不包括注释)。
理由:明确函数功能(一个函数仅完成一件事情),精确(而不是近似)地实现函数设计。
#### 2.5.2 将重复使用的代码编写成函数
级别:建议
描述:将重复使用的简单操作编写成函数。
理由:对于重复使用的功能,虽然很简单,也应以函数的形式来处理,这样可以简化代码,使代码更易于维护。
#### 2.5.3 函数声明和定义的格式要求
级别:规则
描述:在声明和定义函数时,在函数参数列表中为各参数指定类型和名称。
理由:提高代码的可读性,改善可移植性。
举例
```cpp
// 不要象下面这样写代码:
f(int, char*); // 函数声明
...
f(int a, char* b) // 函数定义
{
...
}
// 应该这样写:
f(int a, char* b); // 函数声明
...
f(int a, char* b) // 函数定义
{
...
}
```
#### 2.5.4 为函数指定返回值
级别:规则
描述:要为每一个函数指定它的返回值。如果函数没有返回值,则要定义返回类型为 `void`
理由:提高代码的可读性;改善代码的可移植性。
#### 2.5.5 在函数调用语句中不要使用赋值操作符
级别:建议
描述:
函数调用语句中,在函数的参数列表中不要使赋值操作符。
赋值操作符包括: `=, +=, -=, *=, /=, %=, >>=, <<=, &=, |=, !=, ^=, ++, --`
理由:避免产生不明确的赋值顺序。
举例
```cpp
//不要象下面这样写代码:
void fun1(int a);
void fun2(int b)
{
fun1(++b); // 注意这里!
}
```
----
### 2.6 程序组织
对程序组织的要求。
#### 2.6.1 一个头文件中只声明一个函数、一类函数或一个类
级别:规则
描述:
在一个头文件中,只应该包含对一个函数的声明或一类函数的声明,使类时则只包含一个类的声明。
当头文件中包含一类函数时,这些函数功能必须可以抽象为一个共同的单词或短语。
头文件是指以 `.h` 为后缀的文件
理由:提高代码的可读性和文件级别重的可能性。
#### 2.6.2 一个源文件中只实现一个函数、一类函数或一个类
级别:规则
描述:
在一个源文件中,只应该包含对一个函数的定义或一类函数的定义,使类时则只包含一个类的定义。
当源文件中包含一类函数时,这些函数功能必须可以抽象为一个共同的单词或短语。
源文件指以 `.c` 为后缀的代码文件。
理由:提高代码的可读性和文件级别重的可能性。
#### 2.6.3 头文件中只包含声明,不应包含定义
级别:规则
描述:
在头文件中只包含声明,不要包含全局变量和函数的定义。
但宏和 `const` 要分情况讨论,不一定受本规则限制。
理由:在头文件中只应该包含各种声明,而不应该包含具体的实现。
#### 2.6.4 源文件中不要有函数的声明
级别:规则
描述:
在源文件中只应该包含对全局变量、文件作域变量、和函数的定义,不应该包含任何声明。
声明应该统一放到头文件中去。但宏和 `const` 要分情况讨论,不一定受本规则限
理由:内外有别,限制细节知悉范围,提高代码的可读性和可靠性。
#### 2.6.5 可被包含的文件
级别:规则
描述:只允许头文件被包含到其它的代码文件中去。
理由:改善程序代码的组织结构。
#### 2.6.6 避免头文件的重复包含
级别:规则
描述:头文件的格式应该类似于:
```cpp
#ifndef <IDENT>
#define <IDENT>
...
#endif
// 或者
#if !defined(<IDENT>)
#define <IDENT>
...
#endif
```
上面的 `<IDENT>` 是一个标识字符串,要求该标识字符串必须唯一。
建议使用该文件的大写文件名。
理由:避免对同一头文件的重复包含。
举例:
```cpp
// 对于文件 `audit.h`,它的文件结构应该为:
#ifndef AUDIT_H // 第一行
#define AUDIT_H // 第二行
...
#endif // 最后一行
```
----
### 2.7 公共变量
对公共变量(全局变量)的要求。
#### 2.7.1 严格限制公共变量的使用
级别:建议
描述:
在程序中要尽可能少的使公共变量。
在决定使用一个公共变量时,要仔细考虑,权衡得失。
理由:公共变量会增大模块间的耦合,甚至扩大错误传播范围。
#### 2.7.2 明确公共变量的定义
级别:规则
描述:
当你真的决定使用公共变量时,要仔细定义并明确公共变量的含义、作用、取值范围、与其它变量间的关系。
明确公共变量与操作此公共变量的函数之间的关系,如访问、修改和创建等。
#### 2.7.3 防止公共变量与局部变量重名
级别:规则
描述:防止公共变量与局部变量重名。
----
### 2.8 类
对类的要求。
#### 2.8.1 关于默认构造函数
规范级别:规则
规则描述:为每一个类显示定义默认构造函数。
理由:确保类的编写者考虑在类对象初始化时,可能出现的各种情况。
举例
```cpp
class CMyClass
{
CMyClass();
...
};
```
#### 2.8.2 关于拷贝构造函数
规范级别:规则
规则描述:
当类中包含指针类型的数据成员时,必须显示的定义拷贝构造函数。
建议为每个类都显示定义拷贝构造函数。
理由:确保类的编写者考虑类对象在被拷贝时可能出现的各种情况。
举例,
```cpp
class CMyClass
{
CMyClass(CMyClass& object);
...
};
```
#### 2.8.3 为类重载 `=` 操作符
规范级别:规则
规则描述:
当类中包含指针类型的数据成员时,必须显示重载 `=` 操作符。
建议为每个类都显示重载 `=` 操作符。
理由:确保类的编写者考虑将一个该类对象赋值给另一个该类的对象时,可能出现的各种情况。
举例:
```cpp
//应该这样写代码
class CMyClass
{
...
operator = (const CMyClass& object);
...
};
```
#### 2.8.4 关于析构函数
规范级别:规则
规则描述:为每一个类显示的定义析构函数。
理由:确保类的编写者考虑类对象在析构时,可能出现的各种情况。
举例
```cpp
class CMyClass
{
...
~CMyClass();
...
};
```
#### 2.8.5 虚拟析构函数
该规则参考自《Effective C++》中的条款14。
规范级别:规则
规则描述:基类的析构函数一定要为虚拟函数(virtual Destructor)
理由:保证类对象内存被释放之前,基类和派生类的析构函数都被调用。
#### 2.8.6 不要重新定义继承来的非虚函数
规范级别:规则
规则描述:
在派生类中不要对基类中的非虚函数重新进行定义。
如果确实需要在派生类中对该函数进行不同的定义,那么应该在基类中将该函数声明为虚函数;
理由不要忘了,当通过一个指向对象的指针调用成员函数时,最终调用哪个函数取决于指针本身的类型,而不是指针当前所指向的对象。
#### 2.8.7 如果重载了操作符 `new`,也应该重载操作符 `delete`
该规则参考自《Effective C++》中的条款10。
规范级别:规则
规则描述:如果你为一个类重载了操作符 `new`,那你也应该为这个类重载操作符 `delete`
理由:操作符 `new` 和操作符 `delete` 需要一起合作。
#### 2.8.9 类数据成员的访问控制
规范级别:规则
规则描述:类对外的接囗应该是完全功能化的,类中可以定义 `public` 的成员函数,但不应
该有 `public` 的数据成员。
理由:
要想改变对象的当前状态,应该通过它的成员函数来实现,而不应该通过直接设置它的数据成员这种方法。
一个类的数据成员应该声明为 `private` 的,最起码也应该是 `protected` 的。
#### 2.8.10 限制类继承的层数
规范级别:建议
规则描述:当继承的层数超过5层时,问题就很严重了,需要有特别的理由和解释。
理由:
+ 很深的继承通常意味着未做通盘的考虑;
+ 会显著降低效率;
+ 可以尝试用类的组合代替过多的继承;
+ 与此类似,同层类的个数也不能太多,否则应该考虑是否要增加一个父类,
以便做某种程度上的新的抽象,从而减少同层类的个数。
#### 2.8.11 慎用/最好不用多继承
规范级别:建议
规则描述:
C++ 提供多继承的枳制。
多继承在描述某些事物时可能是非常有利的,甚至是必须的,
但我们在使用多继承的时,一定要慎重,在决定使用多继承时,确实要有非常充分的理由。
理由:
多继承会显著增加代码的复杂性,还会带来潜在的混淆。
比如在很多 C++ 书籍中提到的菱形继承问题
#### 2.8.12 考虑类的复用
规范级别:建议
规则描述:类设计的同时,考虑类的可复用性。
----
### 2.9 其它
下面这几条要求,不适合合并到上面任何一类,所以单独作为一部分。
#### 2.9.1 用常量代替无参数的宏
级别:规则
描述:使 `const` 来定义常量,代替通过宏来定义常量的方法。
理由:在不损失效率的同时,使 `const` 常量比宏更加安全。
举例:
```cpp
// 宏定义的方法
#define string "Hello world!"
#define value 3
// 常量定义的方法可以代替宏,且要更好
const char* string = "Hello world!";
const int value = 3;
```
#### 2.9.2 用内联代替有参数的宏
级别:规则
描述:使 `inline` 关键字声明函数为内联函数,代替有参数的宏。
理由:保证效率和安全,同时提高代码的可读性。
#### 2.9.3 尽量使用 C++ 风格的类型转换
该规则参考自《More Effective C++》中的条款2。
规范级别:建议
规则描述:
C++ 提供的类型转换操作符
`static_cast`, `const_cast`, `dynamic_cast` 和 `reinterpret_cast`
代替 C 风格的类型转换符。
理由:
C 风格的类型转换符有两个缺点:
1. 允许你在任何类型之间进行转换,即使在这些类型之间存在着巨大的不同
2. 在程序语句中难以识别。
#### 2.9.4 将不再使用的代码删掉
级别:规则
描述:将程序中不再到的、注释掉的代码及时清除掉。
理由:
理由不做太多的解释了吧?没有的东西就应该清理掉。
如果觉得这些代码你可能以后会到,可以备份到其它地方,而不要留在正式的版本里
## 3 并不会结束
以上就是我们目前要求 C++ 程序遵守的规范的全部内容。欢迎大家讨论、补充和修订。
================================================
FILE: format/Readme.md
================================================
代码自动格式化
=============
[](http://unlicense.org/)
目前选用 Clang-Format 10,建议自行安装使用。VSCode 自带的为 clang 9 可以根据报错注释掉一部分使用。
- [Clang-Format Style Options — Clang 10 documentation](https://releases.llvm.org/10.0.0/tools/clang/docs/ClangFormatStyleOptions.html)
- [Clang-Format Style Options — Clang 9 documentation](https://releases.llvm.org/9.0.0/tools/clang/docs/ClangFormatStyleOptions.html)
课程要求参见:[Cpp 编码规范](./Cpp编码规范.md)
[Issue #11](https://github.com/profthecopyright/Thunder_Class/issues/11) 里有朋友确认这个是现在用的规范,所以目前以此为准。如果有偏差欢迎及时指出。
## 版权说明
注意到 Cpp 编码规范 版权属于任课老师。
为避免争议并便于其他人使用。除 `Cpp编码规范.md` 以外 `format` 文件夹下的其他的文件无版权限制。
================================================
FILE: format/format文件说明.md
================================================
关于 .clang-format 的说明
====
`.clang-format` 里也会有注释,这里主要记录下跳过了、忽略的那些条目。
----
## 1. 前言
> **规则级**的规范要求学生必须要遵守,建议级的规范学生应尽量遵守。
主要实现了 2.1 节中的格式要求。
下文没有提到的条目意味着可以自动格式化了。
参见 [`.clang-format`](./.clang-format) 文件。
## 2. 编码规范正文
### 2.1 格式
+ 2.1.2 哪里应该使用空格
> 7 - case 的常数表达式之后、default 之后的 `:` 前面,要有一个空格。
第7条暂时无法自动化,甚至会破坏已加入的空格。
故建议使用插件+快捷键进行部分格式化。而不是整个文件格式化
+ 2.1.3 哪里不应该使用空格
> 不要在 :: 前后使用空格。
`::` 后面的空格可以自动删除,前面的不不行。
+ 2.1.6 清晰划分控制语句的语句块
> { 与控制语句同行或者,{ 和 } 单独占一行,与控制语句的首字母应处在同一列上。
示例代码中均使用 `{}` 单独成行的写法。故使用相同风格。
要使用 `{` 与关键字在同一行中的格式,请修改 2.1.6。
+ 2.1.8 一次只声明、定义一个变量
需要个人注意
+ 2.1.9* 在表达式中使用括号
需要个人注意
### 2.2 注释
大多数都需要手动添加。仅实现了 "2.2.7* 行末注释尽量对齐"。
建议第一次写的时候就加上,避免遗漏。
+ 2.2.8 注释量
TODO: 考虑进行 loc 统计
## 2.3+ 剩余的格式要求
剩余的几节更多的是格式化无法自动更正的要求。
不少要求是程序逻辑上的要求,需自行注意。
TODO:
+ 考虑使用代码风格检查。
+ 寻找编译器支持的 flag
================================================
FILE: format/testcase/2.1.1.cpp
================================================
// 2.1.1* 空行的使用
// 4 行 => 格式化到 2 行
void f(void)
{
// 允许头部空行
}
================================================
FILE: format/testcase/2.1.10.cpp
================================================
// [规则] 2.1.10 将操作符 *(Dereferencing)、& 和类型写在一起
// char* c;
char * c;
================================================
FILE: format/testcase/2.1.2.cpp
================================================
/// 2.1.2 哪里应该使用空格
/// 1. 在使用赋值运算符、关系运算符、逻辑运算符、位运算符、算术运算符等二元操作符时,在其两边各加一个空格。
/*
int iCount = 2;
int iSum = (1 < 2) || (1 << 32) + 1;
*/
int iCount=2;
int iSum=(1<2)||(1<<32)+1;
/// 2. 三目运算符的 ? 和 : 前后均各加 1 个空格。
/*
int _ = true ? 1 : 0;
*/
int _ = true?1:0;
/// 3. 函数的各参数间、数组初始化列表的各个初始值间,要用 `,` 和后续一个空格隔开
/*
void GetDate(int x, int y);
int iArr[] = {1, 2, 3};
*/
void GetDate(int x,int y);
void GetDate(int x ,int y);
void GetDate(int x , int y);
int iArr[]={1,2,3};
/// 4. 控制语句 if, for, while, switch 和之后的 ( 之间加一个空格。
/// 5. 控制语句 if, for, while, switch 之后的 ) 与 {
/// 之间加一个空格(同行的情况下)。
/// 目前的设定 `{}` 全部独占一行。故无需测试同行情况
/*
void f(void)
{
int i = 0;
if (true) { i++; }
else { for(;;) { i++; }}
while (i!=0) { i--; }
switch (i)
{
case 0:
case 1:
// no code
break;
default:
break;
}
}
*/
================================================
FILE: format/testcase/2.1.3.cpp
================================================
/// 2.1.3 哪里不应该使用空格
struct A
{
int a;
} sa;
typedef struct A* APtr;
APtr saPtr = &sa;
// 1. 不要在引用操作符前后使用空格。
// 引用操作符指 `.` 和 `->`,以及 `[]`。
// 4. `;` 前不能有空格。
/*
void f(void)
{
int arr[5] = {0};
sa.a;
saPtr->a;
}
*/
void f(void)
{
int arr [5] = {0} ;
sa . a ;
saPtr -> a ;
}
// 2. 不要在 :: 前后使用空格。
/*
std::nullptr_t;
*/
std:: nullptr_t;
// std :: nullptr_t; // 暂不能处理 `::` 前的空格
// 3. 不要在一元操作符和其操作对象之间使用空格,
// 一元操作符包括 ++、--、!、&、* 等。
// 4. `;` 前不能有空格。
/*
void g(void)
{
*saPtr;
&sa;
saPtr++;
saPtr--;
!true == false;
}
*/
void g(void)
{
* saPtr ;
& sa ;
saPtr ++ ;
saPtr -- ;
! true==false ;
}
================================================
FILE: format/testcase/2.1.4.cpp
================================================
/// 2.1.4 缩进
/// 以 4个空格为一个缩进单位
/*
void f(void)
{
if (true)
{
for (;;)
{
do
{
// nothing
} while (true);
}
}
}
*/
void f(void)
{
if (true)
{
for (;;)
{
do
{
// nothing
} while (true);
}
}
}
================================================
FILE: format/testcase/2.1.5.cpp
================================================
/// 2.1.5 长语句的书写格式
int iLooooooooooooooooooooooooooooooooooooooooongName = 0;
/*
int _ = iLooooooooooooooooooooooooooooooooooooooooongName
+ iLooooooooooooooooooooooooooooooooooooooooongName
+ iLooooooooooooooooooooooooooooooooooooooooongName;
*/
int _ = iLooooooooooooooooooooooooooooooooooooooooongName +
iLooooooooooooooooooooooooooooooooooooooooongName +
iLooooooooooooooooooooooooooooooooooooooooongName;
================================================
FILE: format/testcase/2.1.6.cpp
================================================
// 2.1.6 清晰划分控制语句的语句块
// 2. `{` 与控制语句同行或者,`{` 和 `}` 单独占一行,
// 与控制语句的首字母应处在同一列上。
// 3. `}` 单独占一行。但在 do...while 结构中,while 前的 } 不能单独占一行,
// 必须和 `while` 同行。
/*
void f(void)
{
int x = 0;
if (x == 0)
{
return;
}
else
{
while (x > 0)
{
x--;
}
}
do
{
x--;
} while (x != 0);
}
*/
void f(void) {
int x = 0;
if (x == 0) { return; }
else { while (x > 0) { x--; } }
do { x--; } while (x != 0); }
================================================
FILE: format/testcase/2.1.7.cpp
================================================
/// 2.1.7 一行只写一条语句或标号
/// > 一行只写一条程序语句或标号
/*
void f(void)
{
int x = 0;
while (true)
{
x++;
}
}
*/
void f(void) { int x=0; while (true) {x++;}}
/*
void g(void)
{
int x = 0;
switch (x)
{
case 0:
case 1:
case 2:
break;
default:
break;
}
}
*/
void g(void) {
int x=0;
switch(x) {
case 0: case 1: case 2: break;
default: break;
}
}
================================================
FILE: format/testcase/2.2.7.cpp
================================================
// 2.2.7 行末注释尽量对齐
/*
int iCount = 0; // 计数器,表示正在处理第几个数据块
int iNeedSave; // 是否保存从服务器返回的数据
int iBytesWritten; // 写入的数据长度
*/
int iCount = 0; // 计数器,表示正在处理第几个数据块
int iNeedSave; // 是否保存从服务器返回的数据
int iBytesWritten; // 写入的数据长度
================================================
FILE: req/2020C++大作业“雷课堂”V2.md
================================================
# 2020 C++大作业——“雷课堂”(Thunder Class)
针对新型冠状病毒感染肺炎疫情对高校正常开学和课堂教学造成的影响,教 育部要求 2020 年春季学期延期开学,以阻断疫情向校园蔓延,并印发了《关于 在疫情防控期间做好普通高等学校在线教学组织与管理工作的指导意见》,提到 “依托各级各类在线课程平台、校内网络学习空间等,积极开展线上授课和线上 学习等在线教学活动,保证疫情防控期间教学进度和教学质量。”
<br/><br/>
清华大学积极响应教育部的号召和要求,以“雨课堂”为主、腾讯会议和 ZOOM 等网络会议软件为辅,2019-2020 春季学期共实现了 4422 门次课程的网 络教学。“雨课堂”以 Office 插件形式,实现一对多的 PPT 展示、在线答题、弹幕、 随机点名等师生互动的交互式教学,并可以汇总关键词、懂/不懂、签到、在线 时长、注意力集中程度、答题情况等群体和个体统计数据,具有独特优势。网络 会议软件在多方语音互动、快速屏幕/窗口共享切换等方面特色突出,但教学信 息统计功能缺失。
<br/><br/>
在本学期 C++课程开始前的系统测试中,有同学建议自主开发一款集合雨 课堂和网络会议优点于一身的网络教学软件(有截图为证,但为了保护这位同学 的人身安全和隐私,就不放图了)。任课教师和助教在充分讨论基础上,决定采 纳这一具有智慧及主动学习特色的建设性意见,并以“雷课堂” (Thunder Class) 为题,设计了本学期的大作业。
<br/><br/>
## 1. 基本功能要求(\*代表教师用户具有的功能)
### 1.1 用户登陆
根据用户名密码登陆软件,三次密码输入错误自动退出雷课堂软
件。根据账号类型(教师/学生)不同自动切换功能。必须包含一个账户名为 Admin,密码为 Admin 的管理员账号,此账号仅能用于管理教师和学生账户的增删改。(不需考虑如何在增删改用户和密码后通知该账户持有者。毕竟
我们有微信)
### 1.2 语音设备选择和切换
教师开始上课前/学生加入课堂前,应可自主选择语音
输入和播放设备;并可在课程持续期间随时切换语音设备。
### 1.3 共享屏幕\*
教师在上课过程中,可共享整个屏幕或某个窗口内容给全体同学 (包括但不限于 PPT 和代码编辑器);可随时切换共享源、停止或再次开始
共享屏幕。
### 1.4 语音直播\*
开始上课时,自动开始语音采集,并实时的通过网络传送给所有
已经连接到本课堂的学生。
### 1.5 随机语音提问\*
教师可一键(单次鼠标点击或单次快捷键)在全体在线同学
中随机选择一名。被选中的同学的麦克风将被自动打开,并发送给教师和其
余全体同学。教师可再次一键结束此次语音提问。
### 1.6 在线发题\*
教师可在上课过程中多次动态编辑并向全体同学发送单选/多选
题,并实时统计个选项选择人数、选择每个选项的同学名单、每位同学作答
的耗时。教师亦可随时中断发题,但仍需统计上述信息
### 1.7 在线答题
学生在收到试题时,应弹出置顶窗口显示题目和选项,并开始计
时。直到学生提交答案或教师中断发题时,才关闭窗口,并将答案和耗时反
馈给教师。
### 1.8 学生签到
进入课堂时自动签到。而教师可收到何时学生签到和退出课堂的
信息。(多次签到和退出均需记录)
### 1.9 注意力
课堂持续期间,学生签到后,“雷课堂软件处于焦点窗口状态的时长”
与学生在线时长的百分比,将在下课时反馈给教师做记录。
### 1.10 上课/下课\*
上课时,教师端开始随时接收用户登录请求,并根据用户名密 码自动决定是否允许学生端连入。一旦允许连入,之后的语音、屏幕共享 均、语音提问、在线答题信息均会传送给该同学。教师下课时,应在接收了 全体在线同学的注意力数据后再断开与学生端的网络连接,之后自动生成 全部课上统计信息,以文件形式存储并在教师端界面上显示。
### 1.11 进入课堂/退出课堂
在输入了教师端的 IP 地址(或 IP 和端口号)后,连 接到教师端,实现进入课堂功能并开始网络数据通信。如在 30 秒内不能连 接到教师端,应弹出提示。在主动退出课堂或直接关闭了软件时,应向教 师端发送注意力数据,再断开与教师端的网络连接。(不需考虑如何获取教 师端 IP 和端口号,毕竟我们有课程微信群)
1.12 麦克风管制
除非收到教师语音提问,否则麦克风时刻处于静音状态。
## 2. 系统设计要求
### 2.1
除程序主函数(广义的主函数,可能是 WinMain 或其他)和必要的友元函数 (要在报告和程序中额外说明每个友元函数的不可替代性:为什么一定要用 友元才能实现)外,不允许出现任何一个非类成员函数。
### 2.2
任何不改变对象状态(不改写自身对象数据成员值)的成员函数均需显示标注 const。
### 2.3
全部类分为三大类:界面类(开发环境提供的、与图形界面相关的类)、业务 流程类(仅有一个,用于和界面实现耦合)、核心类(其余全部类)。仅有界 面类可以用开发环境自动生成代码框架。仅有业务流程类可以包含开发环境 提供类的指针。核心类只允许使用 C++11 支持的标准语法、STL、操作系统 API。(**此条为强烈建议,未实现界面类和核心类分离将严重影响成绩**)
### 2.4
全部语音、屏幕共享、网络传输等需使用操作系统 API 的相关操作,均需封 装成类代码,再被其他核心类使用。不允许其他核心类直接调用操作系统 API。
### 2.5
除界面类外,任何第三方类库的使用,只能处于源代码级别,不可依赖 lib/so/dylib 文件(静态库也不可以)和 DLL 文件。全部第三方类库需在报告 和程序中著名来源和版权信息。
## 3. 代码与发布要求
### 3.1
通过开发环境自动生成的界面类代码,全部数据成员和成员函数需在类声明 时加以注释,函数体内的必要步骤要加以注释。
### 3.2
其他全部类代码的数据成员和成员函数的声明和实现均需加以注释,成员函 数的必要步骤要加以注释。
### 3.3
其他代码规范需遵循学堂发布的编码规范要求。
### 3.4
发布的程序必须是可运行于Win10/Macos10.14操作系统下的32bit或64bit
的 Release 版本:不依赖于具体开发环境的依赖库、不依赖操作系统驱动或 功能模块配置、仅仅软件自身可执行文件和必要的数据库库文件(如使用了 数据库)。在不可避免的依赖数据库驱动时,应提供自动化安装包:运行安装 包即可自动安装和配置数据库驱动、安装软件本身的可执行文件和数据库库 文件。特别地:只要可执行文件和数据库库文件的相对路径不变,数据库驱 动、可执行文件和数据库库文件安装的绝对路径不可影响软件正常运行。 (Mac os 也仅可用 C++编程,不可使用 Object-C、Swift 或其他语言)
## 4. 报告要求
### 4.1
报告应至少包括需求分析、类与类结构设计、界面设计、测试与排错、总结 与体会 5 个部分。
### 4.2 需求分析侧重描述
如何从现实世界提取对象;如何分析功能之间的耦合与 拆分;哪些功能该归属于哪些对象;如何将对象抽象为类。
### 4.3 类与类结构设计侧重描述
有哪些类;每个类存在的必要性和功能性(封装); 类之间如何构成派生或包含关系;具有同一基类的一些列类的功能分配(继 承与多态);其他多态设计(函数重载、模板等)。此部分必须使用 UML 配合 文字描述。
### 4.4 界面设计侧重描述
如何从实用性和便捷性角度设计图形界面;界面与业务 流程如何耦合;如何实现界面与功能的解耦。
### 4.5 测试与排错侧重描述
完成大作业全过程中,遇到的典型错误的表现形式、 定位错误点的判断方法或测试手段;从软件鲁棒性角度实施了那些测试,如 何设计测试计划和安排测试用例。
### 4.6 总结与体会侧重描述
自己大作业的得意之处、神来之笔、闪光的设计思想; 实际实现系统与最初理想目标的差异与不足;通过大作业深入理解了哪些知 识点,锻炼了哪些技能、技巧、技术、思维(举实例说明,不可泛泛而谈); 为帮助下届学弟学妹深入掌握 C++语言与实践技能的建设性意见和建议(特 别是好的大作业可能选题);喜闻乐见及盼望已久的吐槽。
## 5. 大作业分数构成与比例
### 5.1 基本功能分 20%。
以答辩现场测试记录为依据。只考虑功能是否实现、是否 鲁棒,不考虑背后的实现机制。
### 5.2 系统设计分 20%。
以 code review 和报告为依据。不满足本文第 2 部分要求 的:1 点扣 2 分。
### 5.3 代码规范分 20%。
以 code review 和现场测试为依据,每有 1 处违反代码规范要求,扣 1 分,扣完为止。
### 5.4 Release 分 10%。
不满足本文第 3 部分 Release 要求的,不得分。
### 5.5 报告质量分 20%。
以报告编写详实和细致程度为依据,来自多名报告评阅人主观打分的平均值。类及类结构部分的描述可读性、细节丰富性对报告质量 分有贡献,但类与类结构的设计合理性在系统设计分中体现,不计入报告质 量分。
### 5.6 答辩表现分 10%。
以答辩现场测试记录为依据。
### 5.7 额外功能加分不超过 10%。
完成任何超出基本功能要求的、对软件实用性有贡献的额外功能(如摄像头直播、画中画等),最多可获得 10%加分。(加分后总分不会超过 100%)
### 5.8 优秀界面设计加分不超过 5%。
由多名评阅人投票推选不超过总选课人数 10% 的优秀界面设计,根据多名评阅人打分平均分进行加分。(加分后总分不会超过 100%)
## 6. 作业提交
### 6.1
第 14 周周日前,会通过网络学堂公布全体同学用于答辩和测试的账号、密 码。请各位同学提前录入到自己的数据库文件中,便于大作业答辩时,任何 有围观意愿的同学。
### 6.2
第 16 周周日 24 点为作业提交最后截止时间,以网络学堂计时为准,不接受 任何理由、任何方式的补交。**请充分考虑网络拥堵、本机时间与网络学堂时间不一致等一切可能出现的负面因素,尽早完成并提交大作业。**
### 6.3
提交的内容包括:全部源代码、数据库文件、已在本机编译好的可执行文件 (或安装包)、报告、源代码开发环境版本的说明文件。
## 7、答辩安排
### 7.1
第 17 周周六和周日,采用网络答辩形式,排序名单后续公布。
### 7.2 答辩准备
第 17 周周三前,会通过网络学堂提前发布全体同学提交的可执 行文件(或安装包)和数据库文件,且数据库文件已包含了每位同学的账号
密码。
### 7.3 答辩过程包括
(1)对比双发持有可执行文件的 MD5 码(MD5 码工具另行
发布);
(2)评委用已提交可执行文件以教师账号登录,答辩人以学生账号登 陆,其他围观同学以各自学生账号登陆,在有围观意愿的同学见证下,答辩 人将使用自己提交可执行文件进行答辩和现场测试。与此同时,助教会用微 信与答辩人实时视频,记录答辩人端软件的执行情况。
### 7.4 特别提醒
请在提交作业前进行充分的远程测试和多机连入压力测试。
================================================
FILE: req/readme.md
================================================
## 作业要求
================================================
FILE: src/Qt/adminwindow.cpp
================================================
/***************************************************************
【文件名】 adminwindow.cpp
【功能模块和目的】 管理员窗口
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若修改过则必需注明)
****************************************************************/
#include "adminwindow.h"
#include "../gui/qtguiadaptor.h"
#include "dialogadduser.h"
#include "ui_adminwindow.h"
#include <QMessageBox>
#include <iostream>
/***************************************************************
【函数名称】 构造函数
【函数功能】 设置guiAdaptor指针
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
AdminWindow::AdminWindow(QtGUIAdaptor* w, QWidget* parent)
: QMainWindow(parent), ui(new Ui::AdminWindow)
{
ui->setupUi(this);
this->guiAdaptor = w;
this->dialAdd = new DialogAddUser(this);
}
/***************************************************************
【函数名称】 析构函数
【函数功能】 销毁子窗口
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
AdminWindow::~AdminWindow()
{
delete this->dialAdd;
delete ui;
}
/***************************************************************
【函数名称】 表格添加条目
【函数功能】 在表格中添加显示一条用户信息
【参数】 传入参数,用户信息
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void AdminWindow::tableAddItem(QString id, QString name, QString password,
QString role)
{
int rowCount = ui->tableWidget->rowCount();
this->ui->tableWidget->insertRow(rowCount);
this->ui->tableWidget->setItem(rowCount, 0, new QTableWidgetItem(id));
this->ui->tableWidget->setItem(rowCount, 1, new QTableWidgetItem(name));
this->ui->tableWidget->setItem(rowCount, 2, new QTableWidgetItem(password));
this->ui->tableWidget->setItem(rowCount, 3, new QTableWidgetItem(role));
}
/***************************************************************
【函数名称】 加载列表
【函数功能】 接收用户列表并显示
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void AdminWindow::loadList(std::vector<std::vector<std::string>> table)
{
this->table = table;
for (auto iter = table.begin(); iter != table.end(); iter++) {
try {
this->tableAddItem(QString::fromStdString(iter->at(0)),
QString::fromStdString(iter->at(1)),
QString::fromStdString(iter->at(2)),
QString::fromStdString(iter->at(3)));
}
catch (std::out_of_range& e) {
std::cout << "这一行缺少所需字段:" << iter->at(0) << std::endl;
}
}
}
/***************************************************************
【函数名称】 点击添加按钮
【函数功能】 唤起添加用户对话框
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void AdminWindow::on_pushButton_clicked()
{
this->dialAdd->show();
}
/***************************************************************
【函数名称】 点击删除按钮
【函数功能】 唤起对话框要求用户确认,然后删除对应行
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void AdminWindow::on_pushButton_del_clicked()
{
QString info = "是否删除以下内容?\n";
int i = this->ui->tableWidget->currentRow();
QMessageBox msgBox;
msgBox.setText("确认更改");
msgBox.setInformativeText("是否执行更改:删除第" + QString::number(i + 1)
+ "行");
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
switch (ret) {
case QMessageBox::Ok:
this->ui->tableWidget->removeRow(i);
// his->table.erase(this->table.begin() + i);
break;
case QMessageBox::Cancel:
break;
}
}
/***************************************************************
【函数名称】 点击保存按钮
【函数功能】 向内部发送更新列表消息
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void AdminWindow::on_pushButton_sav_clicked()
{
this->table.clear();
std::vector<std::string> item;
for (int i = 0; i < this->ui->tableWidget->rowCount(); i++) {
for (int j = 0; j < this->ui->tableWidget->columnCount(); j++) {
item.push_back(
this->ui->tableWidget->item(i, j)->text().toStdString());
}
this->table.push_back(item);
item.clear();
}
/*
for (auto iter = this->table.begin(); iter != this->table.end(); iter++) {
std::cout << iter->at(0) << std::endl;
}
*/
this->guiAdaptor->onUserListChange(this->table);
}
================================================
FILE: src/Qt/adminwindow.h
================================================
/***************************************************************
【文件名】 adminwindow.h
【功能模块和目的】 管理员窗口
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若修改过则必需注明)
****************************************************************/
#ifndef ADMINWINDOW_H
#define ADMINWINDOW_H
#include <QMainWindow>
namespace Ui
{
class AdminWindow;
}
/***************************************************************
【类名】 (必需)
【功能】 (必需)
【接口说明】 (必需)
【开发者及日期】 (必需)
【更改记录】 (若修改过则必需注明)
****************************************************************/
class QtGUIAdaptor;
class DialogAddUser;
class AdminWindow: public QMainWindow {
Q_OBJECT
public:
explicit AdminWindow(QtGUIAdaptor*, QWidget* parent = nullptr);
~AdminWindow();
void tableAddItem(QString, QString, QString, QString);
void loadList(std::vector<std::vector<std::string>>);
private slots:
void on_pushButton_clicked();
void on_pushButton_del_clicked();
void on_pushButton_sav_clicked();
public:
std::vector<std::vector<std::string>> table;
private:
Ui::AdminWindow* ui;
QtGUIAdaptor* guiAdaptor;
DialogAddUser* dialAdd;
};
#endif // ADMINWINDOW_H
================================================
FILE: src/Qt/adminwindow.ui
================================================
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AdminWindow</class>
<widget class="QMainWindow" name="AdminWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>雷课堂管理员</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>30</x>
<y>20</y>
<width>151</width>
<height>31</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">font:30px</string>
</property>
<property name="text">
<string>管理员窗口</string>
</property>
</widget>
<widget class="Line" name="line">
<property name="geometry">
<rect>
<x>30</x>
<y>50</y>
<width>731</width>
<height>16</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>520</x>
<y>180</y>
<width>112</width>
<height>32</height>
</rect>
</property>
<property name="text">
<string>添加</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_del">
<property name="geometry">
<rect>
<x>520</x>
<y>220</y>
<width>112</width>
<height>32</height>
</rect>
</property>
<property name="text">
<string>删除</string>
</property>
</widget>
<widget class="QTableWidget" name="tableWidget">
<property name="geometry">
<rect>
<x>30</x>
<y>70</y>
<width>431</width>
<height>471</height>
</rect>
</property>
<column>
<property name="text">
<string>id</string>
</property>
</column>
<column>
<property name="text">
<string>用户名</string>
</property>
</column>
<column>
<property name="text">
<string>密码</string>
</property>
</column>
<column>
<property name="text">
<string>身份</string>
</property>
</column>
</widget>
<widget class="QPushButton" name="pushButton_sav">
<property name="geometry">
<rect>
<x>520</x>
<y>370</y>
<width>112</width>
<height>32</height>
</rect>
</property>
<property name="text">
<string>保存</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
================================================
FILE: src/Qt/classroomwindow.cpp
================================================
/***************************************************************
【文件名】 classroomwindow.cpp
【功能模块和目的】 登录窗口
【开发者及日期】 未完成
【更改记录】 (若修改过则必需注明)
****************************************************************/
#include "classroomwindow.h"
#include "ui_classroomwindow.h"
/***************************************************************
【函数名称】 构造函数
【函数功能】 设置guiAdaptor指针
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
ClassroomWindow::ClassroomWindow(QtGUIAdaptor* w, QWidget* parent)
: QMainWindow(parent), ui(new Ui::ClassroomWindow)
{
ui->setupUi(this);
this->guiAdaptor = w;
}
/***************************************************************
【函数名称】 析构函数
【函数功能】 暂无
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
ClassroomWindow::~ClassroomWindow()
{
delete ui;
}
================================================
FILE: src/Qt/classroomwindow.h
================================================
/***************************************************************
【文件名】 classroomwindow.h
【功能模块和目的】 登录窗口
【开发者及日期】 未完成
【更改记录】 (若修改过则必需注明)
****************************************************************/
#ifndef CLASSROOMWINDOW_H
#define CLASSROOMWINDOW_H
#include <QMainWindow>
namespace Ui
{
class ClassroomWindow;
}
class QtGUIAdaptor;
/***************************************************************
【类名】 ClassroomWindow
【功能】 学生端课室窗口
【接口说明】 无接口
【开发者及日期】 未完成
【更改记录】 (若修改过则必需注明)
****************************************************************/
class ClassroomWindow: public QMainWindow {
Q_OBJECT
public:
explicit ClassroomWindow(QtGUIAdaptor*, QWidget* parent = nullptr);
~ClassroomWindow();
private:
Ui::ClassroomWindow* ui;
QtGUIAdaptor* guiAdaptor;
};
#endif // CLASSROOMWINDOW_H
================================================
FILE: src/Qt/classroomwindow.ui
================================================
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ClassroomWindow</class>
<widget class="QMainWindow" name="ClassroomWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>雷课堂课室</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>40</x>
<y>30</y>
<width>161</width>
<height>31</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">font: 30px</string>
</property>
<property name="text">
<string>雷课堂课室</string>
</property>
</widget>
<widget class="Line" name="line">
<property name="geometry">
<rect>
<x>40</x>
<y>60</y>
<width>721</width>
<height>20</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
<widget class="QGraphicsView" name="graphicsView">
<property name="geometry">
<rect>
<x>40</x>
<y>90</y>
<width>721</width>
<height>441</height>
</rect>
</property>
</widget>
<widget class="QCheckBox" name="checkBox">
<property name="geometry">
<rect>
<x>40</x>
<y>550</y>
<width>86</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>开麦</string>
</property>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>
================================================
FILE: src/Qt/dialogadduser.cpp
================================================
/***************************************************************
【文件名】 dialogadduser.cpp
【功能模块和目的】 管理员窗口中添加新用户的对话框窗口
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若修改过则必需注明)
****************************************************************/
#include "dialogadduser.h"
#include "adminwindow.h"
#include "ui_dialogadduser.h"
/***************************************************************
【函数名称】 构造函数
【函数功能】 设置父窗口指针
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
DialogAddUser::DialogAddUser(AdminWindow* a, QWidget* parent)
: QDialog(parent), ui(new Ui::DialogAddUser)
{
ui->setupUi(this);
this->parent = parent;
this->adminWindow = a;
}
/***************************************************************
【函数名称】 析构函数
【函数功能】 暂无
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
DialogAddUser::~DialogAddUser()
{
delete ui;
}
/***************************************************************
【函数名称】 点击拒绝按钮
【函数功能】 关闭自己窗口
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void DialogAddUser::on_buttonBox_rejected()
{
this->close();
}
/***************************************************************
【函数名称】 点击接受按钮
【函数功能】 暂无
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void DialogAddUser::on_buttonBox_accepted()
{
}
/***************************************************************
【函数名称】 重载接受指令
【函数功能】 添加一行用户信息
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void DialogAddUser::accept()
{
QString id, name, password, role;
id = this->ui->editId->text();
name = this->ui->editName->text();
password = this->ui->editPassword->text();
role = this->ui->chooseRole->currentText();
std::vector<std::string> item;
item.push_back(id.toStdString());
item.push_back(name.toStdString());
item.push_back(password.toStdString());
item.push_back(role.toStdString());
if (id.isEmpty()) {
this->ui->editId->setFocus();
}
else if (name.isEmpty()) {
this->ui->editName->setFocus();
}
else if (password.isEmpty()) {
this->ui->editPassword->setFocus();
}
else {
this->adminWindow->table.push_back(item);
this->adminWindow->tableAddItem(id, name, password, role);
return QDialog::accept();
}
}
================================================
FILE: src/Qt/dialogadduser.h
================================================
/***************************************************************
【文件名】 dialogadduser.h
【功能模块和目的】 管理员窗口中添加新用户的对话框窗口
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若修改过则必需注明)
****************************************************************/
#ifndef DIALOGADDUSER_H
#define DIALOGADDUSER_H
#include <QDialog>
namespace Ui
{
class DialogAddUser;
}
class AdminWindow;
/***************************************************************
【类名】 DialogAddUser
【功能】 管理员添加用户的对话窗口
【接口说明】 无接口
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若修改过则必需注明)
****************************************************************/
class DialogAddUser: public QDialog {
Q_OBJECT
public:
explicit DialogAddUser(AdminWindow*, QWidget* parent = nullptr);
~DialogAddUser();
private slots:
void on_buttonBox_rejected();
void on_buttonBox_accepted();
private:
Ui::DialogAddUser* ui;
QWidget* parent;
AdminWindow* adminWindow;
void accept() override;
};
#endif // DIALOGADDUSER_H
================================================
FILE: src/Qt/dialogadduser.ui
================================================
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogAddUser</class>
<widget class="QDialog" name="DialogAddUser">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>30</x>
<y>240</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QLabel" name="label_name">
<property name="geometry">
<rect>
<x>60</x>
<y>90</y>
<width>51</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>用户名:</string>
</property>
</widget>
<widget class="QLabel" name="label_password">
<property name="geometry">
<rect>
<x>60</x>
<y>140</y>
<width>51</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string> 密码:</string>
</property>
</widget>
<widget class="QLabel" name="label_role">
<property name="geometry">
<rect>
<x>60</x>
<y>200</y>
<width>51</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string> 身份:</string>
</property>
</widget>
<widget class="QLabel" name="label_id">
<property name="geometry">
<rect>
<x>60</x>
<y>40</y>
<width>51</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string> ID:</string>
</property>
</widget>
<widget class="QLineEdit" name="editId">
<property name="geometry">
<rect>
<x>120</x>
<y>40</y>
<width>113</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QLineEdit" name="editName">
<property name="geometry">
<rect>
<x>120</x>
<y>90</y>
<width>113</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QLineEdit" name="editPassword">
<property name="geometry">
<rect>
<x>120</x>
<y>140</y>
<width>113</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QComboBox" name="chooseRole">
<property name="geometry">
<rect>
<x>120</x>
<y>190</y>
<width>111</width>
<height>32</height>
</rect>
</property>
<item>
<property name="text">
<string>student</string>
</property>
</item>
<item>
<property name="text">
<string>teacher</string>
</property>
</item>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DialogAddUser</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DialogAddUser</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
================================================
FILE: src/Qt/loginwindow.cpp
================================================
/***************************************************************
【文件名】 loginwindow.cpp
【功能模块和目的】 登录窗口
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若修改过则必需注明)
****************************************************************/
#include "loginwindow.h"
#include "../gui/qtguiadaptor.h"
#include "ui_loginwindow.h"
/***************************************************************
【函数名称】 构造函数
【函数功能】 设置guiAdaptor指针
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
LoginWindow::LoginWindow(QtGUIAdaptor* w, QWidget* parent)
: QMainWindow(parent), ui(new Ui::LoginWindow)
{
ui->setupUi(this);
this->guiAdaptor = w;
}
/***************************************************************
【函数名称】 析构函数
【函数功能】 无
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
LoginWindow::~LoginWindow()
{
delete ui;
}
/***************************************************************
【函数名称】 点击登录按钮
【函数功能】 向内部发送登录消息
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void LoginWindow::on_loginButton_clicked()
{
std::string username, password;
username = this->ui->userName->text().toStdString();
password = this->ui->userPassword->text().toStdString();
this->guiAdaptor->onLogin(username, password);
}
================================================
FILE: src/Qt/loginwindow.h
================================================
/***************************************************************
【文件名】 loginwindow.h
【功能模块和目的】 登录窗口
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若修改过则必需注明)
****************************************************************/
#ifndef LOGINWINDOW_H
#define LOGINWINDOW_H
#include <QMainWindow>
#include <string>
QT_BEGIN_NAMESPACE
namespace Ui
{
class LoginWindow;
}
QT_END_NAMESPACE
class QtGUIAdaptor;
/***************************************************************
【类名】 LoginWindow
【功能】 登录窗口
【接口说明】 无接口
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若修改过则必需注明)
****************************************************************/
class LoginWindow: public QMainWindow {
Q_OBJECT
public:
LoginWindow(QtGUIAdaptor*, QWidget* parent = nullptr);
~LoginWindow();
private slots:
void on_loginButton_clicked();
private:
Ui::LoginWindow* ui;
QtGUIAdaptor* guiAdaptor;
};
#endif // LOGINWINDOW_H
================================================
FILE: src/Qt/loginwindow.ui
================================================
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LoginWindow</class>
<widget class="QMainWindow" name="LoginWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>445</width>
<height>340</height>
</rect>
</property>
<property name="windowTitle">
<string>登录</string>
</property>
<property name="styleSheet">
<string notr="true">background-color:qconicalgradient(cx:0, cy:0, angle:135, stop:0 rgba(255, 255, 0, 69), stop:0.375 rgba(255, 255, 0, 69), stop:0.423533 rgba(251, 255, 0, 145), stop:0.45 rgba(247, 255, 0, 208), stop:0.477581 rgba(255, 244, 71, 130), stop:0.518717 rgba(255, 218, 71, 130), stop:0.55 rgba(255, 255, 0, 255), stop:0.57754 rgba(255, 203, 0, 130), stop:0.625 rgba(255, 255, 0, 69), stop:1 rgba(255, 255, 0, 69))</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLineEdit" name="userName">
<property name="geometry">
<rect>
<x>140</x>
<y>140</y>
<width>161</width>
<height>31</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">color:rgb(255, 255, 255);
background-color: rgb(63, 126, 237);
font:20px;</string>
</property>
<property name="text">
<string>Admin</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>140</x>
<y>110</y>
<width>71</width>
<height>21</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">font: 20px;
background-color: rgba(255, 255, 255, 0)
</string>
</property>
<property name="text">
<string>用户名:</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>140</x>
<y>190</y>
<width>71</width>
<height>21</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">font:20px;
background-color: rgba(255, 255, 255, 0)
</string>
</property>
<property name="text">
<string>密码:</string>
</property>
</widget>
<widget class="QLineEdit" name="userPassword">
<property name="geometry">
<rect>
<x>140</x>
<y>220</y>
<width>161</width>
<height>31</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">color:rgb(255, 255, 255);
background-color: rgb(65, 128, 243);
font:20px;</string>
</property>
<property name="text">
<string>Admin</string>
</property>
</widget>
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>170</x>
<y>40</y>
<width>91</width>
<height>31</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">font:30px;
background-color: rgba(255, 255, 255, 0)
</string>
</property>
<property name="text">
<string>雷课堂</string>
</property>
</widget>
<widget class="QPushButton" name="loginButton">
<property name="geometry">
<rect>
<x>160</x>
<y>270</y>
<width>112</width>
<height>41</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 255, 255);
background-color: rgb(63, 125, 237);
font:20px;
</string>
</property>
<property name="text">
<string>登录</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>
================================================
FILE: src/Qt/readme.md
================================================
## Qt包依赖项
### LoginWindow
- [x] 登录窗口
### AdminWindow
- [x] 管理员窗口
### DialogAddUser
- [x] 管理员窗口中添加用户的对话框窗口
### SetIPWindow
- [x] 设置服务端 ip 和端口,并申请进入课堂的窗口
### ClassroomWindow
- [ ] 学生上课窗口
### 未命名
- [ ] 学生端做题窗口
### TeachWindow
- [ ] 教师授课窗口
================================================
FILE: src/Qt/setipwindow.cpp
================================================
/***************************************************************
【文件名】 setipwindow.cpp
【功能模块和目的】 设置服务端ip地址的窗口
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若修改过则必需注明)
****************************************************************/
#include "setipwindow.h"
#include "../gui/qtguiadaptor.h"
#include "ui_setipwindow.h"
/***************************************************************
【函数名称】 构造函数
【函数功能】 设置guiAdaptor指针
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
SetIPWindow::SetIPWindow(QtGUIAdaptor* g, QWidget* parent)
: QMainWindow(parent), ui(new Ui::SetIPWindow)
{
ui->setupUi(this);
this->guiAdaptor = g;
}
/***************************************************************
【函数名称】 析构函数
【函数功能】 无
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
SetIPWindow::~SetIPWindow()
{
delete ui;
}
/***************************************************************
【函数名称】 点击申请登录按钮
【函数功能】 发送设置服务端ip地址的消息
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void SetIPWindow::on_loginButton_clicked()
{
std::string ipAdress = this->ui->lineEdit_ip->text().toStdString();
std::string port = this->ui->lineEdit_port->text().toStdString();
this->guiAdaptor->onSetServerIP(ipAdress, port);
}
================================================
FILE: src/Qt/setipwindow.h
================================================
/***************************************************************
【文件名】 setipwindow.h
【功能模块和目的】 设置服务端ip地址的窗口
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若修改过则必需注明)
****************************************************************/
#ifndef SETIPWINDOW_H
#define SETIPWINDOW_H
#include <QMainWindow>
namespace Ui
{
class SetIPWindow;
}
class QtGUIAdaptor;
/***************************************************************
【类名】 SetIPWindow
【功能】 学生端设置服务端ip地址的窗口
【接口说明】 无接口
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若修改过则必需注明)
****************************************************************/
class SetIPWindow: public QMainWindow {
Q_OBJECT
public:
explicit SetIPWindow(QtGUIAdaptor*, QWidget* parent = nullptr);
~SetIPWindow();
private slots:
void on_loginButton_clicked();
private:
Ui::SetIPWindow* ui;
QtGUIAdaptor* guiAdaptor;
};
#endif // SETIPWINDOW_H
================================================
FILE: src/Qt/setipwindow.ui
================================================
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SetIPWindow</class>
<widget class="QMainWindow" name="SetIPWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>346</width>
<height>256</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>90</x>
<y>70</y>
<width>131</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>请输入教师端 IP 地址:</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>90</x>
<y>130</y>
<width>81</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>请输入端口:</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit_ip">
<property name="geometry">
<rect>
<x>90</x>
<y>90</y>
<width>161</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit_port">
<property name="geometry">
<rect>
<x>90</x>
<y>150</y>
<width>161</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="loginButton">
<property name="geometry">
<rect>
<x>110</x>
<y>190</y>
<width>112</width>
<height>32</height>
</rect>
</property>
<property name="text">
<string>申请进入</string>
</property>
</widget>
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>100</x>
<y>20</y>
<width>131</width>
<height>31</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">font:30px</string>
</property>
<property name="text">
<string>进入课堂</string>
</property>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>
================================================
FILE: src/Qt/teachwindow.cpp
================================================
/***************************************************************
【文件名】 teachwindow.cpp
【功能模块和目的】 教学窗口
【开发者及日期】 未完成
【更改记录】 (若修改过则必需注明)
****************************************************************/
#include "teachwindow.h"
#include "ui_teachwindow.h"
/***************************************************************
【函数名称】 构造函数
【函数功能】 设置guiAdaptor指针
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
TeachWindow::TeachWindow(QtGUIAdaptor* w, QWidget* parent)
: QMainWindow(parent), ui(new Ui::TeachWindow)
{
ui->setupUi(this);
this->guiAdaptor = w;
}
/***************************************************************
【函数名称】 析构函数
【函数功能】 暂无
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
TeachWindow::~TeachWindow()
{
delete ui;
}
================================================
FILE: src/Qt/teachwindow.h
================================================
/***************************************************************
【文件名】 teachwindow.h
【功能模块和目的】 教学窗口
【开发者及日期】 未完成
【更改记录】 (若修改过则必需注明)
****************************************************************/
#ifndef TEACHWINDOW_H
#define TEACHWINDOW_H
#include <QMainWindow>
class QtGUIAdaptor;
namespace Ui
{
class TeachWindow;
}
/***************************************************************
【类名】 TeachWindow
【功能】 教师端教学
【接口说明】 无接口
【开发者及日期】 未完成
【更改记录】 (若修改过则必需注明)
****************************************************************/
class TeachWindow: public QMainWindow {
Q_OBJECT
public:
explicit TeachWindow(QtGUIAdaptor*, QWidget* parent = nullptr);
~TeachWindow();
private:
Ui::TeachWindow* ui;
QtGUIAdaptor* guiAdaptor;
};
#endif // TEACHWINDOW_H
================================================
FILE: src/Qt/teachwindow.ui
================================================
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TeachWindow</class>
<widget class="QMainWindow" name="TeachWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>40</x>
<y>30</y>
<width>121</width>
<height>31</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">font:30px;</string>
</property>
<property name="text">
<string>授课窗口</string>
</property>
</widget>
<widget class="Line" name="line">
<property name="geometry">
<rect>
<x>40</x>
<y>60</y>
<width>721</width>
<height>16</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
<widget class="QGraphicsView" name="graphicsView">
<property name="geometry">
<rect>
<x>40</x>
<y>80</y>
<width>721</width>
<height>461</height>
</rect>
</property>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>
================================================
FILE: src/basic/lib/readme.md
================================================
## basic.lib子包:独立API与各种(第三方)基本算法封装
API:静态类,核心类。所有方法均为静态方法,可直接从外部调用。
OSAPIWrapper:特殊核心类,将操作系统API(包括Socket通信,音频及窗口捕获、麦克风控制、文件读写、获取系统时间等)与上层隔离。可能派生Mac和Win版本的子类。
VideoEncoder:核心类。图像/视频压缩算法。如JPEG用离散余弦变换(DCT)。也可考虑FFmpeg。
AudioEncoder:核心类。音频压缩算法。
================================================
FILE: src/basic/readme.md
================================================
## basic包:底层API、算法、各种通信数据结构定义
Data:核心类。定义单个程序内部不同模块之间的数据传输格式(基于原始类型,如未压缩的bitmap图像点阵等)
Message:核心类。定义单个程序内部不同模块之间的消息传输格式,包括数据消息与控制消息两种。数据消息如音频、视频、单选题等数据体量大的消息,其中包装了Data对象。控制消息包括点名、登录登出等。不同类型的消息由宏定义对应的消息码。
InternalEvent:核心类。定义两个方法:eventforGUI()为从核心逻辑TaskController传递给GUIAdaptor的、通常需要对图形用户界面作出响应/改变的控制事件,eventforCore()为从connectionAgent传递给TaskController的事件,一般发生在接收到端口传来的数据时由connectionAgent触发。
Status:核心类。记录程序的运行状态的数据结构(如是server mode还是client mode,当前所有连接的list,日志文件流对象等等)。
+ basic.lib子包:独立API与各种(第三方)基本算法封装
API:静态类,核心类。所有方法均为静态方法,可直接从外部调用。
OSAPIWrapper:特殊核心类,将操作系统API(包括Socket通信,音频及窗口捕获、麦克风控制、文件读写、获取系统时间等)与上层隔离。可能派生Mac和Win版本的子类。
VideoEncoder:核心类。图像/视频压缩算法。如JPEG用离散余弦变换(DCT)。也可考虑FFmpeg。
AudioEncoder:核心类。音频压缩算法。
================================================
FILE: src/core/readme.md
================================================
## core包:业务流程控制及业务逻辑执行
TaskController: 抽象类,核心类,业务逻辑类。定义了对用户在GUI上的操作事件类型(抽象意义上)的响应机制。
TaskExecutor:核心类,实际业务逻辑类。TaskController的实现,具体响应用户操作,并(可能)指派各下级Executor类具体执行。Client Mode的功能主要包括发送登录、注意力、答题、语音消息,接收单选题、音视频、点名消息。
Server Mode的功能主要包括接收登录、注意力、答题、语音消息,发送单选题、音视频、点名消息,维护学生账户数据库(本地csv)、记录服务器日志(本地txt)等。
LoginAgent:负责登录验证相关功能(包括用户账户数据库信息维护)。
ConnectionAgent:负责处理端口连接,发送/接收数据,可__raise一个InternalEvent交由上级TaskExecutor处理。
ServerLogAgent:负责服务器日志记录。原则上收到任何Message以后可以直接调用它向日志文件中写一个记录。
DataAgent:负责serialize/deserialize,即实现内部数据格式(Data对象)和端口可以直接发送的字符串(字节流)之间的转换(可能用到压缩/解压缩算法)。
================================================
FILE: src/core/taskcontroller.cpp
================================================
/***************************************************************
【文件名】 taskcontroller.cpp
【功能模块和目的】 管理任务
【开发者及日期】 未完成
【更改记录】 (若修改过则必需注明)
****************************************************************/
#include "taskcontroller.h"
#include "../gui/guiadaptor.h"
/***************************************************************
【函数名称】 构造函数
【函数功能】 设置guiAdaptor指针
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
TaskController::TaskController(GUIAdaptor* g)
{
this->guiAdaptor = g;
}
/***************************************************************
【函数名称】 析构函数
【函数功能】 无
【参数】 无
【返回值】 无
【开发者及日期】 未完成
【更改记录】 (若有修改,则必需注明)
****************************************************************/
TaskController::~TaskController()
{
}
/***************************************************************
【函数名称】 消息处理函数
【函数功能】 设置guiAdaptor指针
【参数】 无
【返回值】 无
【开发者及日期】 未完成
【更改记录】 (若有修改,则必需注明)
****************************************************************/
int TaskController::respondToGUIMessage(const Message& message)
{
// TODO
}
================================================
FILE: src/core/taskcontroller.h
================================================
/***************************************************************
【文件名】 taskcontroller.h
【功能模块和目的】 管理任务
【开发者及日期】 未完成
【更改记录】 (若修改过则必需注明)
****************************************************************/
#ifndef TASKCONTROLLER_H
#define TASKCONTROLLER_H
#include <string>
#include <vector>
class GUIAdaptor;
class Message;
/***************************************************************
【类名】 TaskController
【功能】 管理任务
【接口说明】 (必需)
【开发者及日期】 (必需)
【更改记录】 (若修改过则必需注明)
****************************************************************/
class TaskController {
public:
TaskController(GUIAdaptor*);
~TaskController();
int respondToGUIMessage(const Message& message);
private:
GUIAdaptor* guiAdaptor;
};
#endif // TASKCONTROLLER_H
================================================
FILE: src/gui/guiadaptor.cpp
================================================
/***************************************************************
【文件名】 guiadaptor.cpp
【功能模块和目的】 GUI包装
【开发者及日期】 未完成
【更改记录】 (若修改过则必需注明)
****************************************************************/
#include "guiadaptor.h"
#include "../core/taskcontroller.h"
//构造与析构
void GUIAdaptor::create()
{
this->taskController = new TaskController(this);
}
void GUIAdaptor::destroy()
{
delete this->taskController;
}
//登录
bool GUIAdaptor::onLogin(std::string name, std::string password)
{
// TODO
return false;
}
bool GUIAdaptor::onExit()
{
// TODO
return false;
}
//管理
bool GUIAdaptor::onUserListChange(std::vector<std::vector<std::string>> table)
{
// TODO
return false;
}
//学生端
bool GUIAdaptor::onSetServerIP(std::string ip, std::string port)
{
// TODO
return false;
}
bool GUIAdaptor::onStartAudioShare()
{
// TODO
return false;
}
bool GUIAdaptor::onCloseAudioShare()
{
// TODO
}
std::vector<std::string> GUIAdaptor::onRequireAudioOutputDevices()
{
// TODO
// return false;
}
bool GUIAdaptor::onSelectAudioOutputDevice(int rank)
{
// TODO
return false;
}
bool GUIAdaptor::onSetMute(bool b)
{
// TODO
return false;
}
bool GUIAdaptor::onSelectAudioInputDevice(int rank)
{
// TODO
return false;
}
std::vector<std::string> GUIAdaptor::onRequireAudioInputDevices()
{
// TODO
// return false;
}
bool GUIAdaptor::onCommitAnswer()
{
// TODO
return false;
}
bool GUIAdaptor::onFocusChange(bool ifFocused)
{
// TODO
return false;
}
//教师端
bool GUIAdaptor::onRaiseTest()
{
// TODO
return false;
}
bool GUIAdaptor::onCloseTest()
{
// TODO
return false;
}
bool GUIAdaptor::onAskStudent()
{
// TODO
return false;
}
bool GUIAdaptor::onAskStudent(std::string name)
{
// TODO
return false;
}
bool GUIAdaptor::onCloseAskStudent()
{
// TODO
return false;
}
bool GUIAdaptor::onMicControl(bool ifAllow)
{
// TODO
return false;
}
================================================
FILE: src/gui/guiadaptor.h
================================================
/***************************************************************
【文件名】 guiadaptor.h
【功能模块和目的】 GUI包装
【开发者及日期】 未完成
【更改记录】 (若修改过则必需注明)
****************************************************************/
#ifndef WORKFLOW_H
#define WORKFLOW_H
#include <string>
#include <vector>
class TaskController;
/***************************************************************
【类名】 GUIAdaptor
【功能】 GUI包装
【接口说明】 字面意思理解即可
【开发者及日期】 (必需)
【更改记录】 (若修改过则必需注明)
****************************************************************/
class GUIAdaptor {
public:
//构造与析构
void create();
void destroy();
//登录
bool onLogin(std::string, std::string);
bool onExit();
//管理
bool onUserListChange(std::vector<std::vector<std::string>>);
//学生端
bool onSetServerIP(std::string, std::string);
bool onStartAudioShare();
bool onCloseAudioShare();
std::vector<std::string> onRequireAudioOutputDevices();
bool onSelectAudioOutputDevice(int);
bool onSetMute(bool);
bool onSelectAudioInputDevice(int);
std::vector<std::string> onRequireAudioInputDevices();
bool onCommitAnswer();
bool onFocusChange(bool);
//教师端
bool onRaiseTest();
bool onCloseTest();
bool onAskStudent();
bool onAskStudent(std::string);
bool onCloseAskStudent();
bool onMicControl(bool);
virtual void quitApplication() = 0;
//登录
virtual bool closeLoginWindow() = 0;
virtual void showLoginWindow() = 0;
//课室相关
virtual void showClassroomWindow() = 0;
virtual bool closeClassroomWindow() = 0;
//管理相关
virtual void showAdminWindow(std::vector<std::vector<std::string>>) = 0;
virtual bool closeAdminWindow() = 0;
private:
TaskController* taskController;
};
#endif // WORKFLOW_H
================================================
FILE: src/gui/qtguiadaptor.cpp
================================================
/***************************************************************
【文件名】 qtguiadaptor.cpp
【功能模块和目的】 实现GUI接口
【开发者及日期】 未完成
【更改记录】 (若修改过则必需注明)
****************************************************************/
#include "qtguiadaptor.h"
#include "../Qt/adminwindow.h"
#include "../Qt/classroomwindow.h"
#include "../Qt/loginwindow.h"
#include "../Qt/setipwindow.h"
#include "../Qt/teachwindow.h"
/***************************************************************
【函数名称】 main
【函数功能】 创建一个业务流程类,开发阶段用来测试代码
【参数】 输入参数
【返回值】 正常返回0
【开发者及日期】 测试代码无需留名
【更改记录】 (若有修改,则必需注明)
****************************************************************/
int main(int argc, char* argv[])
{
QtGUIAdaptor workflow(argc, argv);
std::vector<std::vector<std::string>> table;
std::vector<std::string> item;
item.push_back("测试id");
item.push_back("测试名");
item.push_back("测试密码");
item.push_back("测试身份");
table.push_back(item);
item.push_back("测试id2");
item.push_back("测试名2");
item.push_back("测试密码2");
item.push_back("测试身份2");
table.push_back(item);
workflow.showAdminWindow(table);
return workflow.app->exec();
}
/***************************************************************
【函数名称】 构造函数
【函数功能】 创建一个app,并执行基类的构造
【参数】 输入参数
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
QtGUIAdaptor::QtGUIAdaptor(int argc, char* argv[])
{
this->app = new QApplication(argc, argv);
this->loginWindow = new LoginWindow(this);
this->create();
}
/***************************************************************
【函数名称】 析构函数
【函数功能】 销毁app,销毁可能创建的窗口,并执行基类的析构
【参数】 输入参数
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
QtGUIAdaptor::~QtGUIAdaptor()
{
this->destroy();
if (this->loginWindow != nullptr) {
delete this->loginWindow;
}
if (this->classroomWindow != nullptr) {
delete this->classroomWindow;
}
if (this->adminWindow != nullptr) {
delete this->classroomWindow;
}
if (this->teachWindow != nullptr) {
delete this->classroomWindow;
}
if (this->setIPWindow != nullptr) {
delete this->classroomWindow;
}
delete this->app;
}
/***************************************************************
【函数名称】 退出程序
【函数功能】 提供退出程序接口
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void QtGUIAdaptor::quitApplication()
{
this->app->exit(0);
}
/***************************************************************
【函数名称】 showLoginWindow
【函数功能】 若无则创建登录窗口,显示登录窗口
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void QtGUIAdaptor::showLoginWindow()
{
if (this->loginWindow == nullptr) {
this->loginWindow = new LoginWindow(this);
}
return this->loginWindow->show();
}
/***************************************************************
【函数名称】 closeLoginWindow
【函数功能】 若有则关闭登录窗口
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
bool QtGUIAdaptor::closeLoginWindow()
{
if (this->loginWindow != nullptr) {
return this->loginWindow->close();
}
return false;
}
//课室相关
/***************************************************************
【函数名称】 showSetIPWindow
【函数功能】 若无则创建ip窗口,显示ip窗口
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void QtGUIAdaptor::showSetIPWindow()
{
if (this->setIPWindow == nullptr) {
this->setIPWindow = new SetIPWindow(this);
}
return this->setIPWindow->show();
}
/***************************************************************
【函数名称】 closeSetIPWindow
【函数功能】 若有则关闭ip窗口
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
bool QtGUIAdaptor::closeSetIPWindow()
{
if (this->setIPWindow != nullptr) {
return this->setIPWindow->close();
}
return false;
}
/***************************************************************
【函数名称】 showClassroomWindow
【函数功能】 若无则创建课室窗口,显示课室窗口
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void QtGUIAdaptor::showClassroomWindow()
{
if (this->classroomWindow == nullptr) {
this->classroomWindow = new ClassroomWindow(this);
}
return this->classroomWindow->show();
}
/***************************************************************
【函数名称】 closeClassroomWindow
【函数功能】 若有则关闭课室窗口
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
bool QtGUIAdaptor::closeClassroomWindow()
{
if (this->classroomWindow != nullptr) {
return this->classroomWindow->close();
}
return false;
}
//授课相关
/***************************************************************
【函数名称】 showTeachWindow
【函数功能】 若无则创建授课窗口,显示授课窗口
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void QtGUIAdaptor::showTeachWindow()
{
if (this->classroomWindow == nullptr) {
this->classroomWindow = new ClassroomWindow(this);
}
return this->loginWindow->show();
}
/***************************************************************
【函数名称】 closeTeachWindow
【函数功能】 若有则关闭授课窗口
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
bool QtGUIAdaptor::closeTeachWindow()
{
if (this->teachWindow != nullptr) {
return this->teachWindow->close();
}
return false;
}
//管理员相关
/***************************************************************
【函数名称】 showAdminWindow
【函数功能】 若无则创建管理员窗口,显示管理员窗口
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
void QtGUIAdaptor::showAdminWindow(std::vector<std::vector<std::string>> table)
{
// std::cout << "调用" << table[0][0] << std::endl;
if (this->adminWindow == nullptr) {
this->adminWindow = new AdminWindow(this);
}
this->adminWindow->loadList(table);
return this->adminWindow->show();
}
/***************************************************************
【函数名称】 closeAdminWindow
【函数功能】 若有则关闭管理员窗口
【参数】 无
【返回值】 无
【开发者及日期】 cnDengyu, 2020/04/29
【更改记录】 (若有修改,则必需注明)
****************************************************************/
bool QtGUIAdaptor::closeAdminWindow()
{
if (this->adminWindow != nullptr) {
return this->adminWindow->close();
}
return false;
}
================================================
FILE: src/gui/qtguiadaptor.h
================================================
/***************************************************************
【文件名】 qtguiadaptor.h
【功能模块和目的】 实现GUI接口
【开发者及日期】 未完成
【更改记录】 (若修改过则必需注明)
****************************************************************/
#ifndef QTWORKFLOW_H
#define QTWORKFLOW_H
#include <QApplication>
#include <QString>
#include <string>
#include "guiadaptor.h"
class AdminWindow;
class ClassroomWindow;
class TeachWindow;
class LoginWindow;
class SetIPWindow;
/***************************************************************
【类名】 QtGUIAdaptor
【功能】 实现GUIAdaptor的接口
【接口说明】
【开发者及日期】 未完成
【更改记录】 (若修改过则必需注明)
****************************************************************/
class QtGUIAdaptor: public GUIAdaptor {
public:
QtGUIAdaptor(int argc, char* argv[]);
~QtGUIAdaptor();
//-----------核心类可用的函数-------------------
void quitApplication();
//登录相关
bool closeLoginWindow();
void showLoginWindow();
//课室相关
void showSetIPWindow();
bool closeSetIPWindow();
void showClassroomWindow();
bool closeClassroomWindow();
//授课相关
void showTeachWindow();
bool closeTeachWindow();
//管理相关
void showAdminWindow(std::vector<std::vector<std::string>>);
bool closeAdminWindow();
QApplication* app;
private:
LoginWindow* loginWindow;
SetIPWindow* setIPWindow;
ClassroomWindow* classroomWindow;
TeachWindow* teachWindow;
AdminWindow* adminWindow;
};
#endif // QTWORKFLOW_H
================================================
FILE: src/gui/readme.md
================================================
## gui包:GUI相关
GUIAdaptor: 业务流程类,抽象类,负责上层GUI与下层核心业务逻辑之间的通信。依赖于TaskController(拥有其指针)国。GUI对核心的汇报通过调用TaskController定义的各接口方法完成;核心对GUI的汇报通过__raise关键字产生InnerEvent类型的事件实现,该事件将被GUIAdaptor相应,从而改变GUI。main函数直接创建GUIAdaptor对象,由其进一步引导程序启动流程,如创建GUI窗体和TaskController、引导登录等。
QtGUIAdaptor: GUIAdaptor的子类,一种基于Qt的GUI实现(同理还可基于MFC实现;基于Qt的实现也可有不同的界面样式等等)。
================================================
FILE: src/prototype/readme.md
================================================
## 程序原型/核心技术展示
独立于主程序开发各包,作教学/说明/简单调试之用。
展示各种技术(音视频压缩、__event机制、端口传输等)的小程序
================================================
FILE: src/readme.md
================================================
## 源码目录
================================================
FILE: trash/UML_Demo.txt
================================================
@startuml
skinparam classAttributeIconSize 0
abstract class User {
-name:String
+getName():String
}
User <|.. ClientUser
User <|.. ServerUser
User ..> OSAPIWrapper
User ..> Message
Workflow ..> User
Workflow ..> GUIClasses
@enduml
================================================
FILE: trash/readme.md
================================================
## 没什么太大用但暂时不想删的东西
================================================
FILE: trash/初步流程计划.md
================================================
## 第一轮迭代(如果还有第二轮的话)流程初步想法
第一轮迭代coding框架预备主要由我来搭建,有强烈兴趣此时加入的可以表个态。关于设计/架构/库选择方面的意见和建议可以随时提,但非至关重要的实施/修改请等到第一轮迭代完成之后加入。目前的最高优先级任务是先搭一个粗糙但能用的框架出来,让所有人都有一个扩展/修订的基础。之后会更多鼓励大家参与贡献。
Step 1. 实现基于Winsock的TCP通讯,传输的信息可以很简单,比如一个简单的C++对象,但要实现Multicast和简单的消息响应机制(搞个函数出来,不一定做什么事情,就把消息打印在console就可以)。
Step 2. 实现Server(Admin账户)的数据库管理功能,数据库可以暂时只用一个本地的csv文件维护,密码明文存储就可以了。
Step 3. 实现Client和Server之间通讯的指令消息相关功能(除音视频之外的功能:上下课、点名、状态维护、日志记录etc)
Step 4. 图形用户界面设计,把1-3的相关功能整合进来。留出视频的位置。
Step 5. 窗口/屏幕捕获、音视频压制、FFmpeg推流。Step 5可以和2-4独立开发。显示视频本身肯定会自带一个GUI窗口,和4最好可以先分离后整合。
Step 6. 测试、文档、代码风格、杂七杂八。
PS:类图、用例图什么的到时候再画吧,最好在Step 1完成的时候有个初稿。肯定是要边画边改的(狗头)。
## 其余各种需求暂且待第一轮迭代结束后再次分析。预备list:
1. Mac的Socket通讯与GUI
2. 视情况优化传输协议
3. GUI美化?
================================================
FILE: trash/类图plantUML.txt
================================================
@startuml
skinparam classAttributeIconSize 0
package basic
{
class OSAPIWrapper
class AudioEncoder
class VideoEncoder
class Status
class InternalEvent
class NetworkMessage
}
package core
{
class TaskController
class TaskExecutor
}
package gui
{
class GUIAdaptor
class QtGUIAdaptor
}
package Qt
{
class QtGUIWindow
class QTimer
}
abstract class TaskController
{
+ isServer: bool
+ {abstract} doLogin():void
}
note top of TaskController: Abstract class, as a delegate of Server or Client TaskController in the program
class InternalEvent
{
-eventId:int
-eventData:DataType
}
note bottom of InternalEvent: Event generated by TaskController object to change GUI and handled by GUIAdaptor
class Status
{
-connectionList: vector<string>
}
abstract class GUIAdaptor
{
-TaskController:TaskController
__ pseudo constructors and destructors __
+ create():void
+ destroy():void
__ Handlers of Events generated by GUI __
+ {abstract} onLogin(string, string):int
+ {abstract} onAdminChangeList():void
+ {abstract} onRequireAudioOutputList():vector<string>
+ {abstract} onRequireAudioInputList():vector<string>
+ {abstract} onSelectAudioOutput():int
+ {abstract} onSelectAudioInput():int
+ {abstract} onShareScreen():void
+ {abstract} onShareAudio():void
+ {abstract} onRaiseQuestion():void
+ {abstract} onCreateTest():void
+ {abstract} onStudentEnter():void
+ {abstract} onFocusChange():void
__ Handlers of InternalEvents generated by TaskController object __
..Login/Logout..
+ {abstract} closeLoginWindow():bool
+ {abstract} showLoginWindow():void
+ {abstract} quitApplication():void
..Classroom..
+ {abstract} showClassroomWindow():void
+ {abstract} closeClassroomWindow():bool
..Management..
+ {abstract} showAdminWindow():void
+ {abstract} closeAdminWindow():bool
+ {abstract} addShowTaskControllers(string, string, string, string):void
}
note top of GUIAdaptor: Abstract class for workflow control logic (independent of specific GUI implementation)
class QtGUIAdaptor
{
-window:QtGUIWindow
}
note top of QtGUIAdaptor: Implementation of GUIAdaptor bound to a specific type of GUIWindow (Qt)
GUIAdaptor <|.. QtGUIAdaptor
TaskController <|.. TaskExecutor
TaskExecutor ..> OSAPIWrapper
TaskExecutor ..> NetworkMessage
TaskExecutor ..> Status
TaskExecutor ..> InternalEvent
TaskExecutor ..> VideoEncoder
TaskExecutor ..> AudioEncoder
GUIAdaptor ..> TaskController
GUIAdaptor ..>InternalEvent
QtGUIAdaptor ..> QtGUIWindow
QtGUIAdaptor ..> QTimer
note bottom of QtGUIWindow: Specific GUI Window classes (Qt, MFC, etc)
note bottom of NetworkMessage: Message data structures transferred between terminals
note bottom of OSAPIWrapper: Wrapper of Operating System API for insulation
@enduml
================================================
FILE: trash/设计思路.md
================================================
这个文档我会想到哪写到哪,主要是作为一个非正式的思路参考/技术汇总。可能随时会更新(打脸),欢迎补充修正。
## 1. 通信架构
根据要求,同一个程序要按登录方式划分不同用户角色(虽然很奇怪),包括三类:教师、学生、管理员。由于管理员端负责维护账号信息,因此逻辑上讲教师和学生登录时都要先和管理员端建立通信,可把管理员作为Server,教师和学生作为Client(只是功能上的划分),然后Server作为总控分别和各个Client之间建立连接,传输数据(声音+画面的视频流)和控制信息(登录/登出、点名、试题等)。Server很累。演示的时候应该会在同一台机子上同时运行Server和教师端Client(有毒),然后围观/评委以Client形式登录。
更新:有人指出作业的要求是把Admin功能集成在Server上,教师的账户即具管理功能的Admin账户,学生端仅有Client功能。如果是这样的话业务逻辑会更加简化而清晰。
通信协议方面,个人倾向于用UDP而非TCP进行直播流传输,因为可以Multicast而且对数据完整性要求不高(丢就丢了呗,谁家看视频还不卡一下呢)。控制信息的传输理论上可能TCP更安全稳定一些,但本着先完成最基本功能再考虑花里胡哨的原则(俗称迭代开发),先暂时试下都用UDP吧,不行再说。
更正:TCP的声音很强烈,而且UDP的稳定性的确最终是个问题,那就先用TCP吧。
Windows下我用Winsock进行Socket编程(Mac暂且自求多福),简单粗暴还有官方文档。我一般不喜欢搞没用的第三方库,效率足够的话能简单尽量简单。不稳定的传送门:
https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-start-page-2
## 2. 视频/音频流
要求实时传输画面和声音,肯定是要压缩转码的。这个应用似乎对实时性要求还挺高(B站等直播平台的rtmp推流一般都有几分钟的延迟,但点名回答问题/限时作答这种功能还是要延迟能少则少,雨课堂在这方面表现极其差劲),所以可能要在画质和延迟之间进行一个权衡。像Zoom/微信视频这种实时性就比较好(有个好土豆服务器真的很重要)。
这个东西我也没仔细搞过,姑且试试FFmpeg吧。开源的,包含源码,应该至少能用。
https://www.ffmpeg.org/download.html#get-sources
## 3. GUI
个人认为MFC够了,因为暂时不考虑苹果用户的感受(Qt花里胡哨的,但是可以跨平台,希望以后有Contributor做这个)。
## 4. 业务逻辑
整个程序的核心逻辑其实就是个消息驱动的事件响应,只是消息种类多了点,但每一个拆出来并不复杂,Client端要根据Server发来的消息调用相应的功能(播放画面、显示题目),然后也会向Server发送消息(登录、提交题目),Server同时负责维护每个Client的状态并实时更新,顺便记录下日志(小本本)。剩下的像什么捕获窗口啦做题计时器啦都属于犄角旮旯的杂碎功能,找对了API的话一个函数搞定。
gitextract_egk3lt1u/
├── .gitattributes
├── LICENSE
├── README.md
├── bin/
│ └── readme.md
├── doc/
│ ├── readme.md
│ ├── 废话说在前面.md
│ ├── 第一轮迭代正式计划.md
│ ├── 类图plantUML.txt
│ └── 类文档.md
├── format/
│ ├── .clang-format
│ ├── Cpp编码规范.md
│ ├── Readme.md
│ ├── format文件说明.md
│ └── testcase/
│ ├── 2.1.1.cpp
│ ├── 2.1.10.cpp
│ ├── 2.1.2.cpp
│ ├── 2.1.3.cpp
│ ├── 2.1.4.cpp
│ ├── 2.1.5.cpp
│ ├── 2.1.6.cpp
│ ├── 2.1.7.cpp
│ └── 2.2.7.cpp
├── req/
│ ├── 2020C++大作业“雷课堂”V2.md
│ └── readme.md
├── src/
│ ├── Qt/
│ │ ├── adminwindow.cpp
│ │ ├── adminwindow.h
│ │ ├── adminwindow.ui
│ │ ├── classroomwindow.cpp
│ │ ├── classroomwindow.h
│ │ ├── classroomwindow.ui
│ │ ├── dialogadduser.cpp
│ │ ├── dialogadduser.h
│ │ ├── dialogadduser.ui
│ │ ├── loginwindow.cpp
│ │ ├── loginwindow.h
│ │ ├── loginwindow.ui
│ │ ├── readme.md
│ │ ├── setipwindow.cpp
│ │ ├── setipwindow.h
│ │ ├── setipwindow.ui
│ │ ├── teachwindow.cpp
│ │ ├── teachwindow.h
│ │ └── teachwindow.ui
│ ├── basic/
│ │ ├── lib/
│ │ │ └── readme.md
│ │ └── readme.md
│ ├── core/
│ │ ├── readme.md
│ │ ├── taskcontroller.cpp
│ │ └── taskcontroller.h
│ ├── gui/
│ │ ├── guiadaptor.cpp
│ │ ├── guiadaptor.h
│ │ ├── qtguiadaptor.cpp
│ │ ├── qtguiadaptor.h
│ │ └── readme.md
│ ├── prototype/
│ │ └── readme.md
│ └── readme.md
└── trash/
├── UML_Demo.txt
├── readme.md
├── 初步流程计划.md
├── 类图plantUML.txt
├── 设计图草稿(求UML).pptx
└── 设计思路.md
SYMBOL INDEX (25 symbols across 15 files)
FILE: format/testcase/2.1.1.cpp
function f (line 8) | void f(void)
FILE: format/testcase/2.1.3.cpp
type A (line 2) | struct A
type A (line 6) | struct A
function f (line 20) | void f(void)
function g (line 48) | void g(void)
FILE: format/testcase/2.1.4.cpp
function f (line 18) | void f(void)
FILE: format/testcase/2.1.6.cpp
function f (line 29) | void f(void) {
FILE: format/testcase/2.1.7.cpp
function f (line 13) | void f(void) { int x=0; while (true) {x++;}}
function g (line 30) | void g(void) {
FILE: src/Qt/adminwindow.h
function namespace (line 13) | namespace Ui
function class (line 28) | class AdminWindow: public QMainWindow {
FILE: src/Qt/classroomwindow.h
function namespace (line 13) | namespace Ui
function class (line 27) | class ClassroomWindow: public QMainWindow {
FILE: src/Qt/dialogadduser.h
function namespace (line 13) | namespace Ui
function class (line 26) | class DialogAddUser: public QDialog {
FILE: src/Qt/loginwindow.h
function QT_BEGIN_NAMESPACE (line 14) | QT_BEGIN_NAMESPACE
function class (line 30) | class LoginWindow: public QMainWindow {
FILE: src/Qt/setipwindow.h
function namespace (line 13) | namespace Ui
function class (line 26) | class SetIPWindow: public QMainWindow {
FILE: src/Qt/teachwindow.h
function namespace (line 15) | namespace Ui
function class (line 28) | class TeachWindow: public QMainWindow {
FILE: src/core/taskcontroller.h
function class (line 25) | class TaskController {
FILE: src/gui/guiadaptor.h
function class (line 24) | class GUIAdaptor {
FILE: src/gui/qtguiadaptor.cpp
function main (line 23) | int main(int argc, char* argv[])
FILE: src/gui/qtguiadaptor.h
function class (line 31) | class QtGUIAdaptor: public GUIAdaptor {
Condensed preview — 61 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (183K chars).
[
{
"path": ".gitattributes",
"chars": 66,
"preview": "# Auto detect text files and perform LF normalization\n* text=auto\n"
},
{
"path": "LICENSE",
"chars": 35149,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
},
{
"path": "README.md",
"chars": 278,
"preview": "# Thunder_Class\n 不就是个大作业嘛多大点事\n\n [废话说在前面](doc/废话说在前面.md)\n <br/><br/>\n [2020C++大作业“雷课堂”V2作业要求](req/2020C++大作业“雷课堂”V2.md)\n "
},
{
"path": "bin/readme.md",
"chars": 10,
"preview": "## 可执行文件目录"
},
{
"path": "doc/readme.md",
"chars": 13,
"preview": "## 文档/类图/设计流程"
},
{
"path": "doc/废话说在前面.md",
"chars": 1932,
"preview": "## 1. 关于目的\n创建这个repo的初衷可能是帮大家一把,或者证明这个东西没那么难写,或者只是写着玩(类似的蛋疼事情我干过不少,比如用C++从零开始写人工神经网络)etc. 我只负责创建这个repo和这个文档,然后可能不定期出于无聊更新"
},
{
"path": "doc/第一轮迭代正式计划.md",
"chars": 425,
"preview": "## 1. 需求\n音频视频功能简化为传输图片功能,GUI端计时器(注意力功能)暂不实现,其余需求原则上应当实现。\n\n## 2. 流程(同一标号下可并行)\n1. \n- 完善basic中的Data、Message、Status和Internal"
},
{
"path": "doc/类图plantUML.txt",
"chars": 1727,
"preview": "@startuml\n\nskinparam classAttributeIconSize 0\nscale max 50000 height\nscale max 50000 width\n\npackage basic\n{\n\n\tclass Stat"
},
{
"path": "doc/类文档.md",
"chars": 1718,
"preview": "## basic包:底层API、算法、各种通信数据结构定义\n\nData:核心类。定义单个程序内部不同模块之间的数据传输格式(基于原始类型,如未压缩的bitmap图像点阵等)\n\nMessage:核心类。定义单个程序内部不同模块之间的消息传输格"
},
{
"path": "format/.clang-format",
"chars": 4245,
"preview": "---\n# true: 关闭所有规则\nDisableFormat: false\n\n# C++ 语言\nLanguage: Cpp\nStandard: Cpp11\n\n\n## 2. 编码规范正文 ====================="
},
{
"path": "format/Cpp编码规范.md",
"chars": 16306,
"preview": "C++ 程序设计与训练课程编码规范\n============================\n\n\n## 1. 前言\n\n本编码规范针对 C++ 语言。制定本规范的目的:\n\n+ 适用于课下训练、大作业,督促学生养成良好的编码习惯\n+ 提高代码的"
},
{
"path": "format/Readme.md",
"chars": 705,
"preview": "代码自动格式化\n=============\n[](http://unlic"
},
{
"path": "format/format文件说明.md",
"chars": 847,
"preview": "关于 .clang-format 的说明\n====\n\n`.clang-format` 里也会有注释,这里主要记录下跳过了、忽略的那些条目。\n\n----\n\n## 1. 前言\n\n> **规则级**的规范要求学生必须要遵守,建议级的规范学生应尽量"
},
{
"path": "format/testcase/2.1.1.cpp",
"chars": 71,
"preview": "// 2.1.1* 空行的使用\n\n\n\n\n// 4 行 => 格式化到 2 行\n\nvoid f(void)\n{\n\n // 允许头部空行\n}"
},
{
"path": "format/testcase/2.1.10.cpp",
"chars": 69,
"preview": "// [规则] 2.1.10 将操作符 *(Dereferencing)、& 和类型写在一起\n// char* c;\nchar * c;\n"
},
{
"path": "format/testcase/2.1.2.cpp",
"chars": 885,
"preview": "/// 2.1.2 哪里应该使用空格\n\n/// 1. 在使用赋值运算符、关系运算符、逻辑运算符、位运算符、算术运算符等二元操作符时,在其两边各加一个空格。\n/*\nint iCount = 2;\nint iSum = (1 < 2) || ("
},
{
"path": "format/testcase/2.1.3.cpp",
"chars": 695,
"preview": "/// 2.1.3 哪里不应该使用空格\nstruct A\n{\n int a;\n} sa;\ntypedef struct A* APtr;\nAPtr saPtr = &sa;\n\n// 1. 不要在引用操作符前后使用空格。\n// 引用操"
},
{
"path": "format/testcase/2.1.4.cpp",
"chars": 281,
"preview": "/// 2.1.4 缩进\n/// 以 4个空格为一个缩进单位\n/*\nvoid f(void)\n{\n if (true)\n {\n for (;;)\n {\n do\n "
},
{
"path": "format/testcase/2.1.5.cpp",
"chars": 419,
"preview": "/// 2.1.5 长语句的书写格式\nint iLooooooooooooooooooooooooooooooooooooooooongName = 0;\n\n/*\nint _ = iLoooooooooooooooooooooooooooo"
},
{
"path": "format/testcase/2.1.6.cpp",
"chars": 496,
"preview": "// 2.1.6 清晰划分控制语句的语句块\n\n// 2. `{` 与控制语句同行或者,`{` 和 `}` 单独占一行,\n// 与控制语句的首字母应处在同一列上。\n// 3. `}` 单独占一行。但在 do...while 结构中,whil"
},
{
"path": "format/testcase/2.1.7.cpp",
"chars": 451,
"preview": "/// 2.1.7 一行只写一条语句或标号\n/// > 一行只写一条程序语句或标号\n/*\nvoid f(void)\n{\n int x = 0;\n while (true)\n {\n x++;\n }\n}\n*"
},
{
"path": "format/testcase/2.2.7.cpp",
"chars": 228,
"preview": "// 2.2.7 行末注释尽量对齐\n\n/*\nint iCount = 0; // 计数器,表示正在处理第几个数据块\nint iNeedSave; // 是否保存从服务器返回的数据\nint iBytesWritten; // 写"
},
{
"path": "req/2020C++大作业“雷课堂”V2.md",
"chars": 4726,
"preview": "# 2020 C++大作业——“雷课堂”(Thunder Class)\n针对新型冠状病毒感染肺炎疫情对高校正常开学和课堂教学造成的影响,教 育部要求 2020 年春季学期延期开学,以阻断疫情向校园蔓延,并印发了《关于 在疫情防控期间做好普通"
},
{
"path": "req/readme.md",
"chars": 7,
"preview": "## 作业要求"
},
{
"path": "src/Qt/adminwindow.cpp",
"chars": 5133,
"preview": "/***************************************************************\n【文件名】 adminwindow.cpp\n【功能模块和目的】 管理员窗口\n【开发者及日"
},
{
"path": "src/Qt/adminwindow.h",
"chars": 1204,
"preview": "/***************************************************************\n【文件名】 adminwindow.h\n【功能模块和目的】 管理员窗口\n【开发者及日期】"
},
{
"path": "src/Qt/adminwindow.ui",
"chars": 2847,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>AdminWindow</class>\n <widget class=\"QMainWindow\" name="
},
{
"path": "src/Qt/classroomwindow.cpp",
"chars": 1069,
"preview": "/***************************************************************\n【文件名】 classroomwindow.cpp\n【功能模块和目的】 登录窗口\n【开发"
},
{
"path": "src/Qt/classroomwindow.h",
"chars": 879,
"preview": "/***************************************************************\n【文件名】 classroomwindow.h\n【功能模块和目的】 登录窗口\n【开发者及"
},
{
"path": "src/Qt/classroomwindow.ui",
"chars": 1626,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>ClassroomWindow</class>\n <widget class=\"QMainWindow\" n"
},
{
"path": "src/Qt/dialogadduser.cpp",
"chars": 2901,
"preview": "/***************************************************************\n【文件名】 dialogadduser.cpp\n【功能模块和目的】 管理员窗口中添加新用"
},
{
"path": "src/Qt/dialogadduser.h",
"chars": 1037,
"preview": "/***************************************************************\n【文件名】 dialogadduser.h\n【功能模块和目的】 管理员窗口中添加新用户的"
},
{
"path": "src/Qt/dialogadduser.ui",
"chars": 3583,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>DialogAddUser</class>\n <widget class=\"QDialog\" name=\"D"
},
{
"path": "src/Qt/loginwindow.cpp",
"chars": 1616,
"preview": "/***************************************************************\n【文件名】 loginwindow.cpp\n【功能模块和目的】 登录窗口\n【开发者及日期"
},
{
"path": "src/Qt/loginwindow.h",
"chars": 967,
"preview": "/***************************************************************\n【文件名】 loginwindow.h\n【功能模块和目的】 登录窗口\n【开发者及日期】 "
},
{
"path": "src/Qt/loginwindow.ui",
"chars": 3661,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>LoginWindow</class>\n <widget class=\"QMainWindow\" name="
},
{
"path": "src/Qt/readme.md",
"chars": 243,
"preview": "## Qt包依赖项\n\n### LoginWindow\n- [x] 登录窗口\n\n### AdminWindow\n- [x] 管理员窗口\n\n### DialogAddUser\n- [x] 管理员窗口中添加用户的对话框窗口\n\n### SetIPW"
},
{
"path": "src/Qt/setipwindow.cpp",
"chars": 1621,
"preview": "/***************************************************************\n【文件名】 setipwindow.cpp\n【功能模块和目的】 设置服务端ip地址的窗口"
},
{
"path": "src/Qt/setipwindow.h",
"chars": 941,
"preview": "/***************************************************************\n【文件名】 setipwindow.h\n【功能模块和目的】 设置服务端ip地址的窗口\n【"
},
{
"path": "src/Qt/setipwindow.ui",
"chars": 2128,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>SetIPWindow</class>\n <widget class=\"QMainWindow\" name="
},
{
"path": "src/Qt/teachwindow.cpp",
"chars": 1037,
"preview": "/***************************************************************\n【文件名】 teachwindow.cpp\n【功能模块和目的】 教学窗口\n【开发者及日期"
},
{
"path": "src/Qt/teachwindow.h",
"chars": 838,
"preview": "/***************************************************************\n【文件名】 teachwindow.h\n【功能模块和目的】 教学窗口\n【开发者及日期】 "
},
{
"path": "src/Qt/teachwindow.ui",
"chars": 1340,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>TeachWindow</class>\n <widget class=\"QMainWindow\" name="
},
{
"path": "src/basic/lib/readme.md",
"chars": 244,
"preview": "## basic.lib子包:独立API与各种(第三方)基本算法封装\n\nAPI:静态类,核心类。所有方法均为静态方法,可直接从外部调用。\n\nOSAPIWrapper:特殊核心类,将操作系统API(包括Socket通信,音频及窗口捕获、麦克风"
},
{
"path": "src/basic/readme.md",
"chars": 714,
"preview": "## basic包:底层API、算法、各种通信数据结构定义\n\nData:核心类。定义单个程序内部不同模块之间的数据传输格式(基于原始类型,如未压缩的bitmap图像点阵等)\n\nMessage:核心类。定义单个程序内部不同模块之间的消息传输格"
},
{
"path": "src/core/readme.md",
"chars": 567,
"preview": "## core包:业务流程控制及业务逻辑执行\n\nTaskController: 抽象类,核心类,业务逻辑类。定义了对用户在GUI上的操作事件类型(抽象意义上)的响应机制。\n\nTaskExecutor:核心类,实际业务逻辑类。TaskCont"
},
{
"path": "src/core/taskcontroller.cpp",
"chars": 1277,
"preview": "/***************************************************************\n【文件名】 taskcontroller.cpp\n【功能模块和目的】 管理任务\n【开发者"
},
{
"path": "src/core/taskcontroller.h",
"chars": 804,
"preview": "/***************************************************************\n【文件名】 taskcontroller.h\n【功能模块和目的】 管理任务\n【开发者及日"
},
{
"path": "src/gui/guiadaptor.cpp",
"chars": 1980,
"preview": "/***************************************************************\n【文件名】 guiadaptor.cpp\n【功能模块和目的】 GUI包装\n【开发者及日期"
},
{
"path": "src/gui/guiadaptor.h",
"chars": 1807,
"preview": "/***************************************************************\n【文件名】 guiadaptor.h\n【功能模块和目的】 GUI包装\n【开发者及日期】 "
},
{
"path": "src/gui/qtguiadaptor.cpp",
"chars": 7552,
"preview": "/***************************************************************\n【文件名】 qtguiadaptor.cpp\n【功能模块和目的】 实现GUI接口\n【开发"
},
{
"path": "src/gui/qtguiadaptor.h",
"chars": 1478,
"preview": "/***************************************************************\n【文件名】 qtguiadaptor.h\n【功能模块和目的】 实现GUI接口\n【开发者及"
},
{
"path": "src/gui/readme.md",
"chars": 334,
"preview": "## gui包:GUI相关\n\nGUIAdaptor: 业务流程类,抽象类,负责上层GUI与下层核心业务逻辑之间的通信。依赖于TaskController(拥有其指针)国。GUI对核心的汇报通过调用TaskController定义的各接口方法"
},
{
"path": "src/prototype/readme.md",
"chars": 77,
"preview": "## 程序原型/核心技术展示\n\n独立于主程序开发各包,作教学/说明/简单调试之用。\n\n展示各种技术(音视频压缩、__event机制、端口传输等)的小程序\n"
},
{
"path": "src/readme.md",
"chars": 7,
"preview": "## 源码目录"
},
{
"path": "trash/UML_Demo.txt",
"chars": 237,
"preview": "@startuml\n\nskinparam classAttributeIconSize 0\n\n\nabstract class User {\n\t-name:String\n\t+getName():String\n}\n\nUser <|.. Clie"
},
{
"path": "trash/readme.md",
"chars": 18,
"preview": "## 没什么太大用但暂时不想删的东西"
},
{
"path": "trash/初步流程计划.md",
"chars": 706,
"preview": "## 第一轮迭代(如果还有第二轮的话)流程初步想法\n\n第一轮迭代coding框架预备主要由我来搭建,有强烈兴趣此时加入的可以表个态。关于设计/架构/库选择方面的意见和建议可以随时提,但非至关重要的实施/修改请等到第一轮迭代完成之后加入。目前"
},
{
"path": "trash/类图plantUML.txt",
"chars": 2750,
"preview": "@startuml\n\nskinparam classAttributeIconSize 0\n\npackage basic\n{\n\tclass OSAPIWrapper\n\tclass AudioEncoder\n\tclass VideoEncod"
},
{
"path": "trash/设计思路.md",
"chars": 1329,
"preview": "这个文档我会想到哪写到哪,主要是作为一个非正式的思路参考/技术汇总。可能随时会更新(打脸),欢迎补充修正。\n\n## 1. 通信架构\n根据要求,同一个程序要按登录方式划分不同用户角色(虽然很奇怪),包括三类:教师、学生、管理员。由于管理员端负"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the profthecopyright/Thunder_Class GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 61 files (125.3 KB), approximately 45.2k tokens, and a symbol index with 25 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.